GCC Code Coverage Report


Directory: ./
File: storage/innobase/fil/fil0fil.cc
Date: 2022-12-13 11:44:05
Exec Total Coverage
Lines: 3605 4479 80.5%
Branches: 3087 6533 47.3%

Line Branch Exec Source
1 /*****************************************************************************
2
3 Copyright (c) 1995, 2022, Oracle and/or its affiliates.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25 *****************************************************************************/
26
27 /** @file fil/fil0fil.cc
28 The tablespace memory cache */
29
30 #include "my_config.h"
31
32 #include "detail/fil/open_files_limit.h"
33
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <scope_guard.h>
38
39 #include "mysqld.h" // server_uuid
40
41 #include "arch0page.h"
42 #include "btr0btr.h"
43 #include "buf0buf.h"
44 #include "buf0flu.h"
45 #include "dict0boot.h"
46 #include "dict0dd.h"
47 #include "dict0dict.h"
48 #include "fsp0file.h"
49 #include "fsp0fsp.h"
50 #include "fsp0space.h"
51 #include "fsp0sysspace.h"
52 #include "ha_prototypes.h"
53 #include "hash0hash.h"
54 #include "log0buf.h"
55 #include "log0chkp.h"
56 #include "log0recv.h"
57 #include "log0write.h"
58 #include "mach0data.h"
59 #include "mem0mem.h"
60 #include "mtr0log.h"
61 #include "my_dbug.h"
62 #include "ut0new.h"
63
64 #include "clone0api.h"
65 #include "os0file.h"
66 #include "page0zip.h"
67 #include "sql/mysqld.h" // lower_case_file_system
68 #include "srv0srv.h"
69 #include "srv0start.h"
70
71 #include "fil0crypt.h"
72
73 #ifndef UNIV_HOTBACKUP
74 #include "buf0lru.h"
75 #include "ibuf0ibuf.h"
76 #include "os0event.h"
77 #include "row0mysql.h"
78 #include "sql_backup_lock.h"
79 #include "sql_class.h"
80 #include "sync0sync.h"
81 #include "trx0purge.h"
82 #else /* !UNIV_HOTBACKUP */
83 #include <cstring>
84 #include "srv0srv.h"
85 #endif /* !UNIV_HOTBACKUP */
86 #include "system_key.h"
87
88 #include "os0thread-create.h"
89
90 #include "current_thd.h"
91 #include "ha_prototypes.h"
92
93 #include <array>
94 #include <fstream>
95 #include <functional>
96 #include <list>
97 #include <mutex>
98 #include <thread>
99 #include <tuple>
100 #include <unordered_map>
101
102 using Dirs = std::vector<std::string>;
103 using Space_id_set = std::set<space_id_t>;
104
105 constexpr char Fil_path::DB_SEPARATOR;
106 constexpr char Fil_path::OS_SEPARATOR;
107 constexpr const char *Fil_path::SEPARATOR;
108 constexpr const char *Fil_path::DOT_SLASH;
109 constexpr const char *Fil_path::DOT_DOT_SLASH;
110 constexpr const char *Fil_path::SLASH_DOT_DOT_SLASH;
111
112 dberr_t dict_stats_rename_table(const char *old_name, const char *new_name,
113 char *errstr, size_t errstr_sz);
114
115 /** Used for collecting the data in boot_tablespaces() */
116 namespace dd_fil {
117
118 enum {
119 /** DD Object ID */
120 OBJECT_ID,
121
122 /** InnoDB tablspace ID */
123 SPACE_ID,
124
125 /** DD/InnoDB tablespace name */
126 SPACE_NAME,
127
128 /** Path in DD tablespace */
129 OLD_PATH,
130
131 /** Path where it was found during the scan. */
132 NEW_PATH
133 };
134
135 using Moved = std::tuple<dd::Object_id, space_id_t, std::string, std::string,
136 std::string>;
137
138 using Tablespaces = std::vector<Moved>;
139 } // namespace dd_fil
140
141 19024 size_t fil_get_scan_threads(size_t num_files) {
142 /* Number of additional threads required to scan all the files.
143 n_threads == 0 means that the main thread itself will do all the
144 work instead of spawning any additional threads. */
145 19024 size_t n_threads = num_files / FIL_SCAN_MAX_TABLESPACES_PER_THREAD;
146
147 /* Return if no additional threads are needed. */
148
1/2
✓ Branch 0 taken 19024 times.
✗ Branch 1 not taken.
19024 if (n_threads == 0) {
149 19024 return 0;
150 }
151
152 /* Number of concurrent threads supported by the host machine. */
153 size_t max_threads =
154 FIL_SCAN_THREADS_PER_CORE * std::thread::hardware_concurrency();
155
156 /* If the number of concurrent threads supported by the host
157 machine could not be calculated, assume the supported threads
158 to be FIL_SCAN_MAX_THREADS. */
159 max_threads = max_threads == 0 ? FIL_SCAN_MAX_THREADS : max_threads;
160
161 /* Restrict the number of threads to the lower of number of threads
162 supported by the host machine or FIL_SCAN_MAX_THREADS. */
163 if (n_threads > max_threads) {
164 n_threads = max_threads;
165 }
166
167 if (n_threads > FIL_SCAN_MAX_THREADS) {
168 n_threads = FIL_SCAN_MAX_THREADS;
169 }
170
171 return n_threads;
172 }
173
174 /* uint16_t is the index into Tablespace_dirs::m_dirs */
175 using Scanned_files = std::vector<std::pair<uint16_t, std::string>>;
176
177 #ifdef UNIV_PFS_IO
178 mysql_pfs_key_t innodb_tablespace_open_file_key;
179 #endif /* UNIV_PFS_IO */
180
181 /** System tablespace. */
182 fil_space_t *fil_space_t::s_sys_space;
183
184 #ifdef UNIV_HOTBACKUP
185 /** Directories in which remote general tablespaces have been found in the
186 target directory during apply log operation */
187 Dir_set rem_gen_ts_dirs;
188
189 /** true in case the apply-log operation is being performed
190 in the data directory */
191 bool replay_in_datadir = false;
192
193 /* Re-define mutex macros to use the Mutex class defined by the MEB
194 source. MEB calls the routines in "fil0fil.cc" in parallel and,
195 therefore, the mutex protecting the critical sections of the tablespace
196 memory cache must be included also in the MEB compilation of this
197 module. */
198 #undef mutex_create
199 #undef mutex_free
200 #undef mutex_enter
201 #undef mutex_exit
202 #undef mutex_own
203 #undef mutex_validate
204
205 #define mutex_create(I, M) new (M) meb::Mutex()
206 #define mutex_free(M) delete (M)
207 #define mutex_enter(M) (M)->lock()
208 #define mutex_exit(M) (M)->unlock()
209 #define mutex_own(M) 1
210 #define mutex_validate(M) 1
211
212 /** Process a MLOG_FILE_CREATE redo record.
213 @param[in] page_id Page id of the redo log record
214 @param[in] flags Tablespace flags
215 @param[in] name Tablespace filename */
216 static void meb_tablespace_redo_create(const page_id_t &page_id, uint32_t flags,
217 const char *name);
218
219 /** Process a MLOG_FILE_RENAME redo record.
220 @param[in] page_id Page id of the redo log record
221 @param[in] from_name Tablespace from filename
222 @param[in] to_name Tablespace to filename */
223 static void meb_tablespace_redo_rename(const page_id_t &page_id,
224 const char *from_name,
225 const char *to_name);
226
227 /** Process a MLOG_FILE_DELETE redo record.
228 @param[in] page_id Page id of the redo log record
229 @param[in] name Tablespace filename */
230 static void meb_tablespace_redo_delete(const page_id_t &page_id,
231 const char *name);
232
233 #endif /* UNIV_HOTBACKUP */
234
235 /*
236 IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
237 =============================================
238
239 The tablespace cache is responsible for providing fast read/write access to
240 tablespaces. File creation and deletion is done in other modules which know
241 more of the logic of the operation, however.
242
243 Only the system tablespace consists of a list of files. The size of these
244 files does not have to be divisible by the database block size, because
245 we may just leave the last incomplete block unused. When a new file is
246 appended to the tablespace, the maximum size of the file is also specified.
247 At the moment, we think that it is best to extend the file to its maximum
248 size already at the creation of the file, because then we can avoid dynamically
249 extending the file when more space is needed for the tablespace.
250
251 Non system tablespaces contain only a single file.
252
253 A block's position in the tablespace is specified with a 32-bit unsigned
254 integer. The files in the list are thought to be catenated, and the block
255 corresponding to an address n is the nth block in the catenated file (where
256 the first block is named the 0th block, and the incomplete block fragments
257 at the end of files are not taken into account). A tablespace can be extended
258 by appending a new file at the end of the list.
259
260 Our tablespace concept is similar to the one of Oracle.
261
262 To have fast access to a tablespace file, we put the data structures to
263 a hash table. Each tablespace file is given an unique 32-bit identifier,
264 its tablespace ID.
265
266 Some operating systems do not support many open files at the same time, or have
267 a limit set for user or process. Therefore, we put the open files that can be
268 easily closed in an LRU-list. If we need to open another file, we may close the
269 file at the end of the LRU-list. When an I/O-operation is pending on a file, the
270 file cannot be closed - we take the file nodes with pending I/O-operations out
271 of the LRU-list and keep a count of pending operations for each such file node.
272 When an operation completes, we decrement the count and return the file to the
273 LRU-list if the count drops to zero.
274
275 The data structure (Fil_shard) that keeps track of the tablespace ID to
276 fil_space_t* mapping are hashed on the tablespace ID. The tablespace name to
277 fil_space_t* mapping is stored in the same shard. A shard tracks the flushing
278 and open state of a file. When we run out open file handles, we use a ticketing
279 system to serialize the file open, see Fil_shard::reserve_open_slot() and
280 Fil_shard::release_open_slot().
281
282 When updating the global/shared data in Fil_system acquire the mutexes of
283 all shards in ascending order. The shard mutex covers the fil_space_t data
284 members as noted in the fil_space_t and fil_node_t definition. */
285
286 /** Reference to the server data directory. */
287 Fil_path MySQL_datadir_path;
288
289 /** Reference to the server undo directory. */
290 Fil_path MySQL_undo_path;
291
292 /** The undo path is different from any other known directory. */
293 bool MySQL_undo_path_is_unique;
294
295 /** Common InnoDB file extentions */
296 const char *dot_ext[] = {"", ".ibd", ".cfg", ".cfp",
297 ".ibt", ".ibu", ".dblwr", ".bdblwr"};
298
299 /** Number of pending tablespace flushes */
300 ulint fil_n_pending_tablespace_flushes = 0;
301
302 /** Number of files currently open */
303 std::atomic_size_t fil_n_files_open{0};
304
305 /** At this age or older a space/page will be rotated */
306 extern uint srv_fil_crypt_rotate_key_age;
307 extern ib_mutex_t fil_crypt_threads_mutex;
308 extern ib_mutex_t fil_crypt_list_mutex;
309
310 extern uint srv_n_fil_crypt_threads_requested;
311
312 enum fil_load_status {
313 /** The tablespace file(s) were found and valid. */
314 FIL_LOAD_OK,
315
316 /** The name no longer matches space_id */
317 FIL_LOAD_ID_CHANGED,
318
319 /** The file(s) were not found */
320 FIL_LOAD_NOT_FOUND,
321
322 /** The file(s) were not valid */
323 FIL_LOAD_INVALID,
324
325 /** The tablespace file ID in the first page doesn't match
326 expected value. */
327 FIL_LOAD_MISMATCH,
328
329 /** Doublewrite buffer corruption */
330 FIL_LOAD_DBWLR_CORRUPTION
331 };
332
333 /** File operations for tablespace */
334 enum fil_operation_t {
335
336 /** delete a single-table tablespace */
337 FIL_OPERATION_DELETE,
338
339 /** close a single-table tablespace */
340 FIL_OPERATION_CLOSE
341 };
342
343 /** The null file address */
344 fil_addr_t fil_addr_null = {FIL_NULL, 0};
345
346 /** Maximum number of pages to read to determine the space ID. */
347 static const size_t MAX_PAGES_TO_READ = 1;
348
349 #ifndef UNIV_HOTBACKUP
350 /** Maximum number of shards supported. */
351 static const size_t MAX_SHARDS = 68;
352
353 /** Number of undo shards to reserve. */
354 static const size_t UNDO_SHARDS = 4;
355
356 /** The UNDO logs have their own shards (4). */
357 static const size_t UNDO_SHARDS_START = MAX_SHARDS - UNDO_SHARDS;
358 #else /* !UNIV_HOTBACKUP */
359
360 /** Maximum number of shards supported. */
361 static const size_t MAX_SHARDS = 1;
362
363 /** The UNDO logs have their own shards (4). */
364 static const size_t UNDO_SHARDS_START = 0;
365 #endif /* !UNIV_HOTBACKUP */
366
367 /** We want to store the line number from where it was called. */
368 #define mutex_acquire() acquire(__LINE__)
369
370 /** Hash a NUL terminated 'string' */
371 struct Char_Ptr_Hash {
372 /** Hashing function
373 @param[in] ptr NUL terminated string to hash
374 @return the hash */
375 11415766 size_t operator()(const char *ptr) const {
376 11415766 return static_cast<size_t>(ut::hash_string(ptr));
377 }
378 };
379
380 /** Compare two 'strings' */
381 struct Char_Ptr_Compare {
382 /** Compare two NUL terminated strings
383 @param[in] lhs Left hand side
384 @param[in] rhs Right hand side
385 @return true if the contents match */
386 835167 bool operator()(const char *lhs, const char *rhs) const {
387 835167 return (strcmp(lhs, rhs) == 0);
388 }
389 };
390
391 /** Tablespace files discovered during startup. */
392 class Tablespace_files {
393 public:
394 using Names = std::vector<std::string, ut::allocator<std::string>>;
395 using Paths = std::unordered_map<space_id_t, Names>;
396 using Undo_num2id = std::unordered_map<space_id_t, space_id_t>;
397
398 /** Default constructor
399 @param[in] dir Directory that the files are under */
400 explicit Tablespace_files(const std::string &dir);
401
402 /** Add a space ID to filename mapping.
403 @param[in] space_id Tablespace ID
404 @param[in] name File name.
405 @return number of files that map to the space ID */
406 [[nodiscard]] size_t add(space_id_t space_id, const std::string &name);
407
408 /** Get the file names that map to a space ID
409 @param[in] space_id Tablespace ID
410 @return the filenames that map to space id */
411 18873932 [[nodiscard]] Names *find_by_id(space_id_t space_id) {
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18873932 times.
18873932 ut_ad(space_id != TRX_SYS_SPACE);
413
414
2/2
✓ Branch 0 taken 7637979 times.
✓ Branch 1 taken 11235953 times.
18873932 if (undo::is_reserved(space_id)) {
415
1/2
✓ Branch 0 taken 7637979 times.
✗ Branch 1 not taken.
7637979 auto it = m_undo_paths.find(space_id);
416
417
2/2
✓ Branch 0 taken 7442710 times.
✓ Branch 1 taken 195269 times.
7637979 if (it != m_undo_paths.end()) {
418 7442710 return &it->second;
419 }
420
421 } else {
422
1/2
✓ Branch 0 taken 11235953 times.
✗ Branch 1 not taken.
11235953 auto it = m_ibd_paths.find(space_id);
423
424
2/2
✓ Branch 0 taken 10063525 times.
✓ Branch 1 taken 1172428 times.
11235953 if (it != m_ibd_paths.end()) {
425 10063525 return &it->second;
426 }
427 }
428
429 1367697 return nullptr;
430 }
431
432 /** Get the file name that maps to an undo space number
433 @param[in] space_num undo tablespace number
434 @param[out] space_id undo tablespace ID
435 @return the file name that maps to the space number */
436 1217825 [[nodiscard]] Names *find_by_num(space_id_t space_num, space_id_t &space_id) {
437
3/6
✓ Branch 0 taken 1217825 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1217825 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1217825 times.
1217825 ut_ad(space_num > 0 && space_num <= FSP_MAX_UNDO_TABLESPACES);
438
1/2
✓ Branch 0 taken 1217825 times.
✗ Branch 1 not taken.
1217825 auto it_nums = m_undo_nums.find(space_num);
439
2/2
✓ Branch 0 taken 1198875 times.
✓ Branch 1 taken 18950 times.
1217825 if (it_nums == m_undo_nums.end()) {
440 1198875 return (nullptr);
441 }
442 18950 space_id = it_nums->second;
443
444
1/2
✓ Branch 0 taken 18950 times.
✗ Branch 1 not taken.
18950 auto it = m_undo_paths.find(space_id);
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18950 times.
18950 ut_ad(it != m_undo_paths.end());
446
447 18950 return (&it->second);
448 }
449
450 /** Remove the entry for the space ID.
451 @param[in] space_id Tablespace ID mapping to remove
452 @return true if erase successful */
453 6 [[nodiscard]] bool erase_path(space_id_t space_id) {
454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 ut_ad(space_id != TRX_SYS_SPACE);
455
456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (undo::is_reserved(space_id)) {
457 auto n_erased = m_undo_nums.erase(undo::id2num(space_id));
458 ut_ad(n_erased == 1);
459
460 n_erased = m_undo_paths.erase(space_id);
461
462 return (n_erased == 1);
463 } else {
464 6 auto n_erased = m_ibd_paths.erase(space_id);
465
466 6 return (n_erased == 1);
467 }
468 }
469
470 /** Clear all the tablespace data. */
471 9683 void clear() {
472 9683 m_ibd_paths.clear();
473 9683 m_undo_paths.clear();
474 9683 m_undo_nums.clear();
475 9683 }
476
477 /** @return m_dir */
478 52553 const Fil_path &root() const { return m_dir; }
479
480 /** @return the directory path specified by the user. */
481 17623659 const std::string &path() const { return m_dir.path(); }
482
483 private:
484 /* Note: The file names in m_ibd_paths and m_undo_paths are relative
485 to m_real_path. */
486
487 /** Mapping from tablespace ID to data filenames */
488 Paths m_ibd_paths;
489
490 /** Mapping from tablespace ID to Undo files */
491 Paths m_undo_paths;
492
493 /** Mapping from undo space number to space ID */
494 Undo_num2id m_undo_nums;
495
496 /** Top level directory where the above files were found. */
497 Fil_path m_dir;
498 };
499
500 /** Directories scanned during startup and the files discovered. */
501 class Tablespace_dirs {
502 public:
503 using Result = std::pair<std::string, Tablespace_files::Names *>;
504
505 /** Constructor */
506 9805 Tablespace_dirs() : m_dirs(), m_checked() {}
507
508 /** Normalize and save a directory to scan for IBD and IBU datafiles
509 before recovery.
510 @param[in] directory directory to scan for ibd and ibu files
511 @param[in] is_undo_dir true for an undo directory */
512 void set_scan_dir(const std::string &directory, bool is_undo_dir = false);
513
514 /** Normalize and save a list of directories to scan for IBD and IBU
515 datafiles before recovery.
516 @param[in] directories Directories to scan for ibd and ibu files */
517 void set_scan_dirs(const std::string &directories);
518
519 /** Discover tablespaces by reading the header from .ibd files.
520 @return DB_SUCCESS if all goes well */
521 [[nodiscard]] dberr_t scan();
522
523 /** Clear all the tablespace file data but leave the list of
524 scanned directories in place. */
525 9493 void clear() {
526
2/2
✓ Branch 0 taken 9683 times.
✓ Branch 1 taken 9493 times.
19176 for (auto &dir : m_dirs) {
527 9683 dir.clear();
528 }
529
530 9493 m_checked = 0;
531 9493 }
532
533 /** Erase a space ID to filename mapping.
534 @param[in] space_id Tablespace ID to erase
535 @return true if successful */
536 6 [[nodiscard]] bool erase_path(space_id_t space_id) {
537
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 for (auto &dir : m_dirs) {
538
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (dir.erase_path(space_id)) {
539 6 return true;
540 }
541 }
542
543 return false;
544 }
545
546 /* Find the first matching space ID -> name mapping.
547 @param[in] space_id Tablespace ID
548 @return directory searched and pointer to names that map to the
549 tablespace ID */
550 18918891 [[nodiscard]] Result find_by_id(space_id_t space_id) {
551
2/2
✓ Branch 0 taken 18873931 times.
✓ Branch 1 taken 1412657 times.
20286588 for (auto &dir : m_dirs) {
552
1/2
✓ Branch 0 taken 18873931 times.
✗ Branch 1 not taken.
18873931 const auto names = dir.find_by_id(space_id);
553
554
2/2
✓ Branch 0 taken 17506234 times.
✓ Branch 1 taken 1367697 times.
18873931 if (names != nullptr) {
555
1/2
✓ Branch 0 taken 17506234 times.
✗ Branch 1 not taken.
17506234 return (Result{dir.path(), names});
556 }
557 }
558
559
1/2
✓ Branch 0 taken 1412657 times.
✗ Branch 1 not taken.
1412657 return (Result{"", nullptr});
560 }
561
562 /* Find the matching space number ->space ID -> name mapping.
563 @param[in] space_num undo tablespace number
564 @param[out] space_id undo tablespace ID
565 @return directory searched and pointer to name that maps to the
566 tablespace number */
567 1196733 [[nodiscard]] Result find_by_num(space_id_t space_num, space_id_t &space_id) {
568
2/2
✓ Branch 0 taken 1217825 times.
✓ Branch 1 taken 1177783 times.
2395608 for (auto &dir : m_dirs) {
569
1/2
✓ Branch 0 taken 1217825 times.
✗ Branch 1 not taken.
1217825 const auto names = dir.find_by_num(space_num, space_id);
570
571
2/2
✓ Branch 0 taken 18950 times.
✓ Branch 1 taken 1198875 times.
1217825 if (names != nullptr) {
572
1/2
✓ Branch 0 taken 18950 times.
✗ Branch 1 not taken.
18950 return Result{dir.path(), names};
573 }
574 }
575
576
1/2
✓ Branch 0 taken 1177783 times.
✗ Branch 1 not taken.
1177783 return Result{"", nullptr};
577 }
578
579 /** Determine if this Fil_path contains the path provided.
580 @param[in] path file or directory path to compare.
581 @return true if this Fil_path contains path */
582 15110 [[nodiscard]] bool contains(const std::string &path) const {
583
1/2
✓ Branch 0 taken 15110 times.
✗ Branch 1 not taken.
15110 const Fil_path descendant{path};
584
585
2/2
✓ Branch 0 taken 15911 times.
✓ Branch 1 taken 116 times.
16027 for (const auto &dir : m_dirs) {
586
5/6
✓ Branch 0 taken 15911 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6239 times.
✓ Branch 3 taken 9672 times.
✓ Branch 4 taken 14994 times.
✓ Branch 5 taken 917 times.
22150 if (dir.root().is_same_as(descendant) ||
587
3/4
✓ Branch 0 taken 6239 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5322 times.
✓ Branch 3 taken 917 times.
6239 dir.root().is_ancestor(descendant)) {
588 14994 return true;
589 }
590 }
591 116 return false;
592 15110 }
593
594 /** Get the list of directories that InnoDB knows about.
595 @return the list of directories 'dir1;dir2;....;dirN' */
596 9693 std::string get_dirs() const {
597 9693 std::string dirs;
598
599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
9693 ut_ad(!m_dirs.empty());
600
601
2/2
✓ Branch 0 taken 9887 times.
✓ Branch 1 taken 9693 times.
19580 for (const auto &dir : m_dirs) {
602
1/2
✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
9887 dirs.append(dir.root());
603
1/2
✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
9887 dirs.push_back(FIL_PATH_SEPARATOR);
604 }
605
606 9693 dirs.pop_back();
607
608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
9693 ut_ad(!dirs.empty());
609
610 9693 return dirs;
611 }
612
613 private:
614 /** Print the duplicate filenames for a tablespace ID to the log
615 @param[in] duplicates Duplicate tablespace IDs*/
616 void print_duplicates(const Space_id_set &duplicates);
617
618 /** first=dir path from the user, second=files found under first. */
619 using Scanned = std::vector<Tablespace_files>;
620
621 /** Report a warning that a path is being ignored and include the reason. */
622 void warn_ignore(std::string path_in, const char *reason);
623
624 /** Add a single path specification to this list of tablespace directories.
625 Convert it to an absolute path. Check if the path is valid. Ignore
626 unreadable, duplicate or invalid directories.
627 @param[in] str Path specification to tokenize
628 @param[in] is_undo_dir true for an undo directory */
629 void add_path(const std::string &str, bool is_undo_dir = false);
630
631 /** Add a delimited list of path specifications to this list of tablespace
632 directories. Convert relative paths to absolute paths. Check if the paths
633 are valid. Ignore unreadable, duplicate or invalid directories.
634 @param[in] str Path specification to tokenize
635 @param[in] delimiters Delimiters */
636 void add_paths(const std::string &str, const std::string &delimiters);
637
638 using Const_iter = Scanned_files::const_iterator;
639
640 /** Check for duplicate tablespace IDs.
641 @param[in] start Start of slice
642 @param[in] end End of slice
643 @param[in] thread_id Thread ID
644 @param[in,out] mutex Mutex protecting the global state
645 @param[in,out] unique To check for duplicates
646 @param[in,out] duplicates Duplicate space IDs found */
647 void duplicate_check(const Const_iter &start, const Const_iter &end,
648 size_t thread_id, std::mutex *mutex,
649 Space_id_set *unique, Space_id_set *duplicates);
650
651 private:
652 /** Directories scanned and the files discovered under them. */
653 Scanned m_dirs;
654
655 /** Number of files checked. */
656 std::atomic_size_t m_checked;
657 };
658
659 /** Determine if space flushing should be disabled, for example when user has
660 explicitly disabled fsync(). */
661 27910652 static inline bool fil_disable_space_flushing(const fil_space_t *space) {
662 #ifndef _WIN32
663
2/2
✓ Branch 0 taken 26032925 times.
✓ Branch 1 taken 1877727 times.
27910652 if (space->purpose == FIL_TYPE_TABLESPACE &&
664
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 26032826 times.
26032925 srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC) {
665 99 return true;
666 }
667 #endif /* !_WIN32 */
668
2/2
✓ Branch 0 taken 1874890 times.
✓ Branch 1 taken 26035663 times.
27910553 if (space->purpose == FIL_TYPE_TEMPORARY) {
669 1874890 return true;
670 }
671 26035663 return false;
672 }
673
674 class Fil_shard {
675 using File_list = UT_LIST_BASE_NODE_T(fil_node_t, LRU);
676 using Space_list = UT_LIST_BASE_NODE_T(fil_space_t, unflushed_spaces);
677 using Full_space_list = UT_LIST_BASE_NODE_T(fil_space_t, space_list);
678 using Rotation_list = UT_LIST_BASE_NODE_T(fil_space_t, rotation_list);
679 using Spaces = std::unordered_map<space_id_t, fil_space_t *>;
680
681 using Names = std::unordered_map<const char *, fil_space_t *, Char_Ptr_Hash,
682 Char_Ptr_Compare>;
683
684 public:
685 /** Constructor
686 @param[in] shard_id Shard ID */
687 explicit Fil_shard(size_t shard_id);
688
689 /** Destructor */
690 569772 ~Fil_shard() {
691 569772 mutex_destroy(&m_mutex);
692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 569772 times.
569772 ut_a(UT_LIST_GET_LEN(m_LRU) == 0);
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 569772 times.
569772 ut_a(UT_LIST_GET_LEN(m_unflushed_spaces) == 0);
694 569772 }
695
696 /** @return the shard ID */
697 size_t id() const { return m_id; }
698
699 /** Acquire the mutex.
700 @param[in] line Line number from where it was called */
701 2663997833 void acquire(int line) const {
702 #ifndef UNIV_HOTBACKUP
703 2663997833 m_mutex.enter(srv_n_spin_wait_rounds, srv_spin_wait_delay, __FILE__, line);
704 #else
705 mutex_enter(&m_mutex);
706 #endif /* !UNIV_HOTBACKUP */
707 2663512221 }
708
709 /** Release the mutex. */
710 2664196358 void mutex_release() const { mutex_exit(&m_mutex); }
711
712 #ifdef UNIV_DEBUG
713 /** @return true if the mutex is owned. */
714 3866671437 bool mutex_owned() const { return mutex_own(&m_mutex); }
715 #endif /* UNIV_DEBUG */
716
717 /** Acquire a tablespace to prevent it from being dropped concurrently.
718 The thread must call Fil_shard::fil_space_release() when the operation
719 is done.
720 @param[in] space tablespace to acquire
721 @return true if not space->stop_new_ops */
722 bool space_acquire(fil_space_t *space);
723
724 /** Release a tablespace acquired with Fil_shard::space_acquire().
725 @param[in,out] space tablespace to release */
726 void space_release(fil_space_t *space);
727
728 /** Fetch the fil_space_t instance that maps to space_id. Does not look
729 through system reserved spaces.
730 @param[in] space_id Tablespace ID to lookup
731 @return tablespace instance or nullptr if not found. */
732 1391921647 [[nodiscard]] fil_space_t *get_space_by_id_from_map(
733 space_id_t space_id) const {
734
2/4
✓ Branch 0 taken 1391926032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1391924125 times.
1391921647 ut_ad(mutex_owned());
735
736
1/2
✓ Branch 0 taken 1391928007 times.
✗ Branch 1 not taken.
1391924125 auto it = m_spaces.find(space_id);
737
738 /* The system tablespace must always be found */
739
4/8
✓ Branch 0 taken 891489 times.
✓ Branch 1 taken 1391027284 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 891489 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1391918582 times.
1391928007 ut_ad(it != m_spaces.end() || space_id != 0 || srv_is_being_started);
740
741
2/2
✓ Branch 0 taken 891489 times.
✓ Branch 1 taken 1391024281 times.
1391918582 if (it == m_spaces.end()) {
742 891489 return nullptr;
743 }
744
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1391023897 times.
1391024281 ut_ad(it->second->magic_n == FIL_SPACE_MAGIC_N);
746
5/8
✓ Branch 0 taken 1391023096 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1246281820 times.
✓ Branch 3 taken 144741276 times.
✓ Branch 4 taken 1246279899 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1391021357 times.
1391023897 ut_ad(fsp_is_system_temporary(space_id) || it->second->files.size() == 1);
747
748 1391021357 return it->second;
749 }
750
751 /** Fetch the fil_space_t instance that maps to space_id.
752 @param[in] space_id Tablespace ID to lookup
753 @return tablespace instance or nullptr if not found. */
754 fil_space_t *get_space_by_id(space_id_t space_id) const;
755
756 /** Fetch the fil_space_t instance that maps to the name.
757 @param[in] name Tablespace name to lookup
758 @return tablespace instance or nullptr if not found. */
759 10312733 [[nodiscard]] fil_space_t *get_space_by_name(const char *name) const {
760
2/4
✓ Branch 0 taken 10312733 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10312733 times.
10312733 ut_ad(mutex_owned());
761
762
1/2
✓ Branch 0 taken 10312733 times.
✗ Branch 1 not taken.
10312733 auto it = m_names.find(name);
763
764
2/2
✓ Branch 0 taken 9919750 times.
✓ Branch 1 taken 392983 times.
10312733 if (it == m_names.end()) {
765 9919750 return nullptr;
766 }
767
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 392983 times.
392983 ut_ad(it->second->magic_n == FIL_SPACE_MAGIC_N);
769
770 392983 return it->second;
771 }
772
773 /** Tries to close a file in the shard LRU list.
774 The caller must hold the Fil_shard::m_mutex.
775 @return true if success, false if should retry later */
776 [[nodiscard]] bool close_files_in_LRU();
777
778 /** Remove the file node from the LRU list.
779 @param[in,out] file File for the tablespace */
780 void remove_from_LRU(fil_node_t *file);
781
782 /** Add the file node to the LRU list if required.
783 @param[in,out] file File for the tablespace */
784 void add_to_lru_if_needed(fil_node_t *file);
785
786 /** Open all the system files.
787 @param[in] max_n_open Maximum number of open files allowed
788 @param[in,out] n_open Current number of open files */
789 void open_system_tablespaces(size_t max_n_open, size_t *n_open);
790
791 /** Close a tablespace file.
792 @param[in,out] file Tablespace file to close */
793 void close_file(fil_node_t *file);
794
795 /** Close a tablespace file based on tablespace ID.
796 @param[in] space_id Tablespace ID
797 @return false if space_id was not found. */
798 bool close_file(space_id_t space_id);
799
800 /** Prepare to free a file object from a tablespace
801 memory cache.
802 @param[in,out] file Tablespace file
803 @param[in] space tablespace */
804 void file_close_to_free(fil_node_t *file, fil_space_t *space);
805
806 /** Close all open files. */
807 void close_all_files();
808
809 #ifndef UNIV_HOTBACKUP
810 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
811 /** Check that each fil_space_t::m_n_ref_count in this shard matches the
812 number of pages counted in the buffer pool.
813 @param[in] buffer_pool_references Map of spaces instances to the count
814 of their pages in the buffer pool. */
815 void validate_space_reference_count(Space_References &buffer_pool_references);
816 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
817 #endif /* !UNIV_HOTBACKUP */
818
819 /** Determine if the tablespace needs encryption rotation.
820 @param[in] space tablespace to rotate
821 @return true if the tablespace needs to be rotated, false if not. */
822 bool needs_encryption_rotate(fil_space_t *space);
823
824 /** Rotate the tablespace keys by new master key.
825 @param[in,out] rotate_count A cumulative count of all tablespaces rotated
826 in the Fil_system.
827 @return the number of tablespaces that failed to rotate. */
828 [[nodiscard]] size_t encryption_rotate(size_t *rotate_count);
829
830 /** Detach a space object from the tablespace memory cache and
831 closes the tablespace files but does not delete them.
832 There must not be any pending I/O's or flushes on the files.
833 @param[in,out] space tablespace */
834 void space_detach(fil_space_t *space);
835
836 /** Remove the fil_space_t instance from the maps used to search for it.
837 @param[in] space_id Tablespace ID to remove from maps. */
838 187505 void space_remove_from_lookup_maps(space_id_t space_id) {
839
2/4
✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187505 times.
187505 ut_ad(mutex_owned());
840
841
1/2
✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
187505 auto it = m_spaces.find(space_id);
842
843
1/2
✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
187505 if (it != m_spaces.end()) {
844
1/2
✓ Branch 0 taken 187505 times.
✗ Branch 1 not taken.
187505 m_names.erase(it->second->name);
845
1/2
✓ Branch 0 taken 187504 times.
✗ Branch 1 not taken.
187505 m_spaces.erase(it);
846 }
847 187504 }
848
849 #ifndef UNIV_HOTBACKUP
850 /** Move the space to the deleted list and remove from the default
851 lookup set.
852 @param[in, out] space Space instance to delete. */
853 181 void space_prepare_for_delete(fil_space_t *space) noexcept {
854 181 mutex_acquire();
855
856 181 space->set_deleted();
857
858 /* Remove access to the fil_space_t instance. */
859 181 space_remove_from_lookup_maps(space->id);
860
861 181 m_deleted_spaces.push_back({space->id, space});
862
863 181 space_detach(space);
864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
181 ut_a(space->files.size() == 1);
865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
181 ut_a(space->files.front().n_pending_ios == 0);
866
867 181 mutex_release();
868 181 }
869
870 /** Purge entries from m_deleted_spaces that are no longer referenced by a
871 buffer pool page. This is no longer required to be done during checkpoint -
872 this is done here for historical reasons - it has to be done periodically
873 somewhere. */
874 38088024 void purge() {
875 /* Avoid cleaning up old undo files while this is on. */
876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38088024 times.
38088024 DBUG_EXECUTE_IF("ib_undo_trunc_checkpoint_off", return;);
877
878 38088024 mutex_acquire();
879
2/2
✓ Branch 0 taken 682587 times.
✓ Branch 1 taken 38088024 times.
38770611 for (auto it = m_deleted_spaces.begin(); it != m_deleted_spaces.end();) {
880 682587 auto space = it->second;
881
882
3/4
✓ Branch 0 taken 682587 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181544 times.
✓ Branch 3 taken 501043 times.
682587 if (space->has_no_references()) {
883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181544 times.
181544 ut_a(space->files.size() == 1);
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181544 times.
181544 ut_a(space->files.front().n_pending_ios == 0);
885
886
1/2
✓ Branch 0 taken 181544 times.
✗ Branch 1 not taken.
181544 space_free_low(space);
887
888
1/2
✓ Branch 0 taken 181544 times.
✗ Branch 1 not taken.
181544 it = m_deleted_spaces.erase(it);
889 } else {
890 501043 ++it;
891 }
892 }
893
894 38088024 mutex_release();
895 }
896
897 /** Count how many truncated undo space IDs are still tracked in
898 the buffer pool and the file_system cache.
899 @param[in] undo_num undo tablespace number.
900 @return number of undo tablespaces that are still in memory. */
901 3599036 size_t count_undo_deleted(space_id_t undo_num) noexcept {
902 3599036 size_t count = 0;
903
904 3599036 mutex_acquire();
905
906
2/2
✓ Branch 0 taken 167087 times.
✓ Branch 1 taken 3599036 times.
3766123 for (auto deleted : m_deleted_spaces) {
907
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 166943 times.
167087 if (undo::id2num(deleted.first) == undo_num) {
908 144 count++;
909 }
910 }
911
912 3599036 mutex_release();
913
914 3599036 return count;
915 }
916
917 /** Check if a particular space_id for a page in the buffer pool has
918 been deleted recently. Its space_id will be found in m_deleted_spaces
919 until Fil:shard::checkpoint removes the fil_space_t from Fil_system.
920 @param[in] space_id Tablespace ID to check.
921 @return true if this space_id is in the list of recently deleted spaces. */
922 bool is_deleted(space_id_t space_id) {
923 bool found = false;
924
925 mutex_acquire();
926
927 for (auto deleted : m_deleted_spaces) {
928 if (deleted.first == space_id) {
929 found = true;
930 break;
931 }
932 }
933
934 mutex_release();
935
936 return found;
937 }
938
939 #endif /* !UNIV_HOTBACKUP */
940
941 /** Frees a space object from the tablespace memory cache.
942 Closes a tablespaces' files but does not delete them.
943 There must not be any pending I/O's or flushes on the files.
944 @param[in] space_id Tablespace ID
945 @return fil_space_t instance on success or nullptr */
946 [[nodiscard]] fil_space_t *space_free(space_id_t space_id);
947
948 /** Map the space ID and name to the tablespace instance.
949 @param[in] space Tablespace instance */
950 void space_add(fil_space_t *space, fil_encryption_t mode);
951
952 /** Prepare to free a file. Remove from the unflushed list
953 if there are no pending flushes.
954 @param[in,out] file File instance to free */
955 void prepare_to_free_file(fil_node_t *file);
956
957 /** If the tablespace is on the unflushed list and there
958 are no pending flushes then remove from the unflushed list.
959 @param[in,out] space Tablespace to remove*/
960 void remove_from_unflushed_list(fil_space_t *space);
961
962 /** Updates the data structures when an I/O operation
963 finishes. Updates the pending I/O's field in the file
964 appropriately.
965 @param[in] file Tablespace file
966 @param[in] type Marks the file as modified type == WRITE */
967 void complete_io(fil_node_t *file, const IORequest &type);
968
969 /** Prepares a file for I/O. Opens the file if it is closed. Updates the
970 pending I/O's field in the file and the system appropriately. Takes the file
971 off the LRU list if it is in the LRU list.
972 @param[in] file Tablespace file for IO
973 @return false if the file can't be opened, otherwise true */
974 [[nodiscard]] bool prepare_file_for_io(fil_node_t *file);
975
976 /** Remap the tablespace to the new name.
977 @param[in] space Tablespace instance, with old name.
978 @param[in] new_name New tablespace name */
979 void update_space_name_map(fil_space_t *space, const char *new_name);
980
981 /** Flush to disk the writes in file spaces possibly cached by the OS
982 (note: spaces of type FIL_TYPE_TEMPORARY are skipped) */
983 void flush_file_spaces();
984
985 /** Try to extend a tablespace if it is smaller than the specified size.
986 @param[in,out] space tablespace
987 @param[in] size desired size in pages
988 @return whether the tablespace is at least as big as requested */
989 [[nodiscard]] bool space_extend(fil_space_t *space, page_no_t size);
990
991 /** Flushes to disk possible writes cached by the OS. If the space does
992 not exist or is being dropped, does not do anything.
993 @param[in] space_id file space ID (id of tablespace of the database)
994 */
995 void space_flush(space_id_t space_id);
996
997 /** Open a file of a tablespace.
998 The caller must own the shard mutex.
999 @param[in,out] file Tablespace file
1000 @return false if the file can't be opened, otherwise true */
1001 [[nodiscard]] bool open_file(fil_node_t *file);
1002
1003 /** Checks if all the file nodes in a space are flushed. The caller must hold
1004 the fil_system mutex.
1005 @param[in] space Tablespace to check
1006 @return true if all are flushed */
1007 [[nodiscard]] bool space_is_flushed(const fil_space_t *space);
1008
1009 /** Open each file of a tablespace if not already open.
1010 @param[in] space_id tablespace identifier
1011 @retval true if all file nodes were opened
1012 @retval false on failure */
1013 [[nodiscard]] bool space_open(space_id_t space_id);
1014
1015 /** Opens the files associated with a tablespace and returns a
1016 pointer to the fil_space_t that is in the memory cache associated
1017 with a space id.
1018 @param[in] space_id Get the tablespace instance or this ID
1019 @return file_space_t pointer, nullptr if space not found */
1020 [[nodiscard]] fil_space_t *space_load(space_id_t space_id);
1021
1022 /** Wait for pending operations on a tablespace to stop.
1023 @param[in] space_id Tablespace ID
1024 @param[out] space tablespace instance in memory
1025 @param[out] path tablespace path
1026 @return DB_SUCCESS or DB_TABLESPACE_NOT_FOUND. */
1027 [[nodiscard]] dberr_t wait_for_pending_operations(space_id_t space_id,
1028 fil_space_t *&space,
1029 char **path) const;
1030
1031 /** Rename a single-table tablespace.
1032 The tablespace must exist in the memory cache.
1033 @param[in] space_id Tablespace ID
1034 @param[in] old_path Old file name
1035 @param[in] new_name New tablespace name in the schema/space
1036 @param[in] new_path_in New file name, or nullptr if it
1037 is located in the normal data directory
1038 @return InnoDB error code */
1039 [[nodiscard]] dberr_t space_rename(space_id_t space_id, const char *old_path,
1040 const char *new_name,
1041 const char *new_path_in);
1042
1043 /** Deletes an IBD or IBU tablespace.
1044 The tablespace must be cached in the memory cache. This will delete the
1045 datafile, fil_space_t & fil_node_t entries from the file_system_t cache.
1046 @param[in] space_id Tablespace ID
1047 @param[in] buf_remove Specify the action to take on the pages
1048 for this table in the buffer pool.
1049 @return DB_SUCCESS, DB_TABLESPCE_NOT_FOUND or DB_IO_ERROR */
1050 [[nodiscard]] dberr_t space_delete(space_id_t space_id,
1051 buf_remove_t buf_remove);
1052
1053 /** Truncate the tablespace to needed size.
1054 @param[in] space_id Tablespace ID to truncate
1055 @param[in] size_in_pages Truncate size.
1056 @return true if truncate was successful. */
1057 [[nodiscard]] bool space_truncate(space_id_t space_id,
1058 page_no_t size_in_pages);
1059
1060 /** Create a space memory object and put it to the fil_system hash table.
1061 The tablespace name is independent from the tablespace file-name.
1062 Error messages are issued to the server log.
1063 @param[in] name Tablespace name
1064 @param[in] space_id Tablespace identifier
1065 @param[in] flags Tablespace flags
1066 @param[in] purpose Tablespace purpose
1067 @return pointer to created tablespace, to be filled in with fil_node_create()
1068 @retval nullptr on failure (such as when the same tablespace exists) */
1069 [[nodiscard]] fil_space_t *space_create(
1070 const char *name, space_id_t space_id, uint32_t flags, fil_type_t purpose,
1071 fil_space_crypt_t *crypt_data,
1072 fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT);
1073
1074 /** Adjust temporary auto-generated names created during
1075 file discovery with correct tablespace names from the DD.
1076 @param[in,out] space Tablespace
1077 @param[in] dd_space_name Tablespace name from the DD
1078 @return true if the tablespace is a general or undo tablespace. */
1079 bool adjust_space_name(fil_space_t *space, const char *dd_space_name);
1080
1081 /** Returns true if a matching tablespace exists in the InnoDB
1082 tablespace memory cache.
1083 @param[in] space_id Tablespace ID
1084 @param[in] name Tablespace name used in fil_space_create().
1085 @param[in] print_err Print detailed error information to the
1086 error log if a matching tablespace is
1087 not found from memory.
1088 @param[in] adjust_space Whether to adjust space id on mismatch
1089 @return true if a matching tablespace exists in the memory cache */
1090 [[nodiscard]] bool space_check_exists(space_id_t space_id, const char *name,
1091 bool print_err, bool adjust_space);
1092
1093 /** Read or write data. This operation could be asynchronous (aio).
1094 @param[in] type IO context
1095 @param[in] sync whether synchronous aio is desired
1096 @param[in] page_id page id
1097 @param[in] page_size page size
1098 @param[in] byte_offset remainder of offset in bytes; in AIO this must
1099 be divisible by the OS block size
1100 @param[in] len how many bytes to read or write; this
1101 must not cross a file boundary; in AIO this must be a block size multiple
1102 @param[in,out] buf buffer where to store read data or from
1103 where to write; in AIO this must be appropriately aligned
1104 @param[in] message message for AIO handler if !sync, else ignored
1105 @param[in] should_buffer whether to buffer an aio request. AIO read
1106 ahead uses this. If you plan to use this parameter, make sure you remember to
1107 call os_aio_dispatch_read_array_submit() when you're ready to commit all your
1108 requests.
1109 @return error code
1110 @retval DB_SUCCESS on success
1111 @retval DB_TABLESPACE_DELETED if the tablespace does not exist */
1112 [[nodiscard]] dberr_t do_io(const IORequest &type, bool sync,
1113 const page_id_t &page_id,
1114 const page_size_t &page_size, ulint byte_offset,
1115 ulint len, void *buf, void *message, trx_t *trx,
1116 bool should_buffer);
1117
1118 /** Iterate through all persistent tablespace files (FIL_TYPE_TABLESPACE)
1119 returning the nodes via callback function f.
1120 @param[in] f Callback
1121 @return any error returned by the callback function. */
1122 [[nodiscard]] dberr_t iterate(Fil_iterator::Function &f);
1123
1124 /** Open an ibd tablespace and add it to the InnoDB data structures.
1125 This is similar to fil_ibd_open() except that it is used while
1126 processing the redo and DDL log, so the data dictionary is not
1127 available and very little validation is done. The tablespace name
1128 is extracted from the dbname/tablename.ibd portion of the filename,
1129 which assumes that the file is a file-per-table tablespace. Any name
1130 will do for now. General tablespace names will be read from the
1131 dictionary after it has been recovered. The tablespace flags are read
1132 at this time from the first page of the file in validate_for_recovery().
1133 @param[in] space_id tablespace ID
1134 @param[in] path path/to/databasename/tablename.ibd
1135 @param[out] space the tablespace, or nullptr on error
1136 @return status of the operation */
1137 [[nodiscard]] fil_load_status ibd_open_for_recovery(space_id_t space_id,
1138 const std::string &path,
1139 fil_space_t *&space);
1140
1141 /** Attach a file to a tablespace
1142 @param[in] name file name of a file that is not open
1143 @param[in] size file size in entire database blocks
1144 @param[in,out] space tablespace from fil_space_create()
1145 @param[in] is_raw whether this is a raw device or partition
1146 @param[in] punch_hole true if supported for this file
1147 @param[in] atomic_write true if the file has atomic write enabled
1148 @param[in] max_pages maximum number of pages in file
1149 @return pointer to the file name
1150 @retval nullptr if error */
1151 [[nodiscard]] fil_node_t *create_node(const char *name, page_no_t size,
1152 fil_space_t *space, bool is_raw,
1153 bool punch_hole, bool atomic_write,
1154 page_no_t max_pages = PAGE_NO_MAX);
1155
1156 #ifdef UNIV_DEBUG
1157 /** Validate a shard. */
1158 void validate() const;
1159 #endif /* UNIV_DEBUG */
1160
1161 #ifdef UNIV_HOTBACKUP
1162 /** Extends all tablespaces to the size stored in the space header.
1163 During the mysqlbackup --apply-log phase we extended the spaces
1164 on-demand so that log records could be applied, but that may have
1165 left spaces still too small compared to the size stored in the space
1166 header. */
1167 void meb_extend_tablespaces_to_stored_len();
1168 #endif /* UNIV_HOTBACKUP */
1169
1170 /** Free a tablespace object on which fil_space_detach() was invoked.
1171 There must not be any pending I/O's or flushes on the files.
1172 @param[in,out] space tablespace */
1173 static void space_free_low(fil_space_t *&space);
1174
1175 private:
1176 /** We keep system tablespace files always open; this is important
1177 in preventing deadlocks in this module, as a page read completion
1178 often performs another read from the insert buffer. The insert buffer
1179 is in tablespace TRX_SYS_SPACE, and we cannot end up waiting in this
1180 function.
1181 @param[in] space_id Tablespace ID to look up
1182 @return tablespace instance */
1183 [[nodiscard]] fil_space_t *get_reserved_space(space_id_t space_id);
1184
1185 /** Prepare for truncating a single-table tablespace.
1186 1) Wait for pending operations on the tablespace to stop;
1187 2) Remove all insert buffer entries for the tablespace;
1188 @param[in] space_id Tablespace ID
1189 @param[out] space Instance that maps to the space ID.
1190 @return DB_SUCCESS or error */
1191 [[nodiscard]] dberr_t space_prepare_for_truncate(space_id_t space_id,
1192 fil_space_t *&space);
1193
1194 /** Note that a write IO has completed.
1195 @param[in,out] file File on which a write was completed */
1196 void write_completed(fil_node_t *file);
1197
1198 /** If the tablespace is not on the unflushed list, add it.
1199 @param[in,out] space Tablespace to add */
1200 void add_to_unflushed_list(fil_space_t *space);
1201
1202 /** Check for pending operations.
1203 @param[in] space tablespace
1204 @param[in] count number of attempts so far
1205 @return 0 if no pending operations else count + 1. */
1206 [[nodiscard]] ulint space_check_pending_operations(fil_space_t *space,
1207 ulint count) const;
1208
1209 /** Check for pending IO.
1210 @param[in] space Tablespace to check
1211 @param[in] file File in space list
1212 @param[in] count number of attempts so far
1213 @return 0 if no pending else count + 1. */
1214 [[nodiscard]] ulint check_pending_io(const fil_space_t *space,
1215 const fil_node_t &file,
1216 ulint count) const;
1217
1218 /** First we open the file in the normal mode, no async I/O here, for
1219 simplicity. Then do some checks, and close the file again. NOTE that we
1220 could not use the simple file read function os_file_read() in Windows
1221 to read from a file opened for async I/O!
1222 @param[in,out] file Get the size of this file
1223 @param[in] read_only_mode true if read only mode set
1224 @return DB_SUCCESS or error */
1225 [[nodiscard]] dberr_t get_file_size(fil_node_t *file, bool read_only_mode);
1226
1227 /** Get the AIO mode.
1228 @param[in] req_type IO request type
1229 @param[in] sync true if Synchronous IO
1230 return the AIO mode */
1231 [[nodiscard]] static AIO_mode get_AIO_mode(const IORequest &req_type,
1232 bool sync);
1233
1234 /** Get the file name for IO and the local offset within that file.
1235 @param[in,out] space Tablespace for IO
1236 @param[in,out] page_no The relative page number in the file
1237 @param[out] file File node if DB_SUCCESS, NULL if not
1238 @retval DB_SUCCESS if the file is found with the page_no
1239 @retval DB_ERROR if the file is not found or does not contain the page.
1240 in this case file == nullptr */
1241 [[nodiscard]] static dberr_t get_file_for_io(fil_space_t *space,
1242 page_no_t *page_no,
1243 fil_node_t *&file);
1244
1245 private:
1246 /** Fil_shard ID */
1247 const size_t m_id;
1248
1249 /** Tablespace instances hashed on the space id */
1250 Spaces m_spaces;
1251
1252 /** Tablespace instances hashed on the space name */
1253 Names m_names;
1254
1255 #ifndef UNIV_HOTBACKUP
1256 using Pair = std::pair<space_id_t, fil_space_t *>;
1257 using Deleted_spaces = std::vector<Pair, ut::allocator<Pair>>;
1258
1259 /** Deleted tablespaces. All pages for these tablespaces in the buffer pool
1260 will be passively deleted. They need not be written. Once the reference count
1261 is zero, this fil_space_t can be deleted from m_deleted_spaces and removed
1262 from memory. All reads and writes must be done under the shard mutex. */
1263 Deleted_spaces m_deleted_spaces;
1264 #endif /* !UNIV_HOTBACKUP */
1265
1266 /** Base node for the LRU list of the most recently used open
1267 files with no pending I/O's; if we start an I/O on the file,
1268 we first remove it from this list, and return it to the start
1269 of the list when the I/O ends; the system tablespace file is
1270 not put to this list: it is opened after the startup, and kept
1271 open until shutdown */
1272
1273 File_list m_LRU;
1274
1275 /** Base node for the list of those tablespaces whose files contain unflushed
1276 writes; those spaces have at least one file where modification_counter >
1277 flush_counter */
1278 Space_list m_unflushed_spaces;
1279
1280 /** When we write to a file we increment this by one */
1281 int64_t m_modification_counter;
1282
1283 /** Mutex protecting this shard. */
1284 #ifndef UNIV_HOTBACKUP
1285 mutable ib_mutex_t m_mutex;
1286 #else
1287 mutable meb::Mutex m_mutex;
1288 #endif /* !UNIV_HOTBACKUP */
1289
1290 // Disable copying
1291 Fil_shard(Fil_shard &&) = delete;
1292 Fil_shard(const Fil_shard &) = delete;
1293 Fil_shard &operator=(Fil_shard &&) = delete;
1294 Fil_shard &operator=(const Fil_shard &) = delete;
1295
1296 friend class Fil_system;
1297
1298 public:
1299 // list of spaces kept in this shard
1300 Full_space_list m_space_list;
1301 Rotation_list m_rotation_list;
1302 };
1303
1304 /** The tablespace memory cache */
1305 class Fil_system {
1306 public:
1307 using Fil_shards = std::vector<Fil_shard *>;
1308
1309 /** Constructor.
1310 @param[in] n_shards Number of shards to create
1311 @param[in] max_open Maximum number of open files */
1312 Fil_system(size_t n_shards, size_t max_open);
1313
1314 /** Destructor */
1315 ~Fil_system();
1316
1317 /** Acquire a tablespace when it could be dropped concurrently.
1318 Used by background threads that do not necessarily hold proper locks
1319 for concurrency control.
1320 @param[in] space_id Tablespace ID
1321 @param[in] silent Whether to silently ignore missing tablespaces
1322 @return the tablespace, or nullptr if missing or being deleted */
1323 fil_space_t *space_acquire(space_id_t space_id, bool silent);
1324
1325 /** Fetch the file names opened for a space_id during recovery.
1326 @param[in] space_id Tablespace ID to lookup
1327 @return pair of top level directory scanned and names that map
1328 to space_id or nullptr if not found. */
1329 18918891 [[nodiscard]] Tablespace_dirs::Result get_scanned_filename_by_space_id(
1330 space_id_t space_id) {
1331 18918891 return m_dirs.find_by_id(space_id);
1332 }
1333
1334 /** Fetch the file name opened for an undo space number.
1335 @param[in] space_num undo tablespace numb er to lookup
1336 @param[out] space_id Tablespace ID found
1337 @return pair of top level directory scanned and name that maps
1338 to the space_num or nullptr if not found. */
1339 1196733 [[nodiscard]] Tablespace_dirs::Result get_scanned_filename_by_space_num(
1340 space_id_t space_num, space_id_t &space_id) {
1341 1196733 return (m_dirs.find_by_num(space_num, space_id));
1342 }
1343
1344 /** Fetch the file name opened for a space_id from the file map.
1345 @param[in] space_id tablespace ID
1346 @param[out] name the scanned filename
1347 @return true if the space_id is found. The name is set to an
1348 empty string if the space_id is not found. */
1349 4 [[nodiscard]] bool get_file_by_space_id(space_id_t space_id,
1350 std::string &name) {
1351
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 auto result = get_scanned_filename_by_space_id(space_id);
1352
1353
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (result.second != nullptr) {
1354 /* Duplicates should have been sorted out by now. */
1355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 ut_a(result.second->size() == 1);
1356
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 name = result.first + result.second->front();
1357 4 return true;
1358 }
1359
1360 name = "";
1361 return false;
1362 4 }
1363
1364 /** Fetch the file name opened for an undo space number.
1365 @param[in] space_num undo tablespace number
1366 @param[out] space_id tablespace ID
1367 @param[out] name the scanned filename
1368 @return true if the space_id is found. The name is set to an
1369 empty string if the space_id is not found. */
1370 1196733 [[nodiscard]] bool get_file_by_space_num(space_id_t space_num,
1371 space_id_t &space_id,
1372 std::string &name) {
1373
1/2
✓ Branch 0 taken 1196733 times.
✗ Branch 1 not taken.
1196733 auto result = get_scanned_filename_by_space_num(space_num, space_id);
1374
1375
2/2
✓ Branch 0 taken 18950 times.
✓ Branch 1 taken 1177783 times.
1196733 if (result.second != nullptr) {
1376 /* Duplicates should have been sorted out by now. */
1377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18950 times.
18950 ut_a(result.second->size() == 1);
1378
1/2
✓ Branch 0 taken 18950 times.
✗ Branch 1 not taken.
18950 name = result.first + result.second->front();
1379 18950 return true;
1380 }
1381
1382
1/2
✓ Branch 0 taken 1177783 times.
✗ Branch 1 not taken.
1177783 name = "";
1383 1177783 return false;
1384 1196733 }
1385
1386 /** Erase a tablespace ID and its mapping from the scanned files.
1387 @param[in] space_id Tablespace ID to erase
1388 @return true if successful */
1389 6 [[nodiscard]] bool erase_path(space_id_t space_id) {
1390 6 return m_dirs.erase_path(space_id);
1391 }
1392
1393 /** Add file to old file list. The list is used during 5.7 upgrade failure
1394 to revert back the modified file names. We modify partitioned file names
1395 to lower case.
1396 @param[in] file_path old file name with path */
1397 407 void add_old_file(const std::string &file_path) {
1398 407 m_old_paths.push_back(file_path);
1399 407 }
1400
1401 /** Rename partition files during upgrade.
1402 @param[in] revert if true, revert to old names */
1403 void rename_partition_files(bool revert);
1404
1405 /** Clear all accumulated old files. */
1406 8379 void clear_old_files() { m_old_paths.clear(); }
1407
1408 /** Get the top level directory where this filename was found.
1409 @param[in] path Path to look for.
1410 @return the top level directory under which this file was found. */
1411 [[nodiscard]] const std::string &get_root(const std::string &path) const;
1412
1413 /** Update the DD if any files were moved to a new location.
1414 Free the Tablespace_files instance.
1415 @param[in] read_only_mode true if InnoDB is started in
1416 read only mode.
1417 @return DB_SUCCESS if all OK */
1418 [[nodiscard]] dberr_t prepare_open_for_business(bool read_only_mode);
1419
1420 /** Flush to disk the writes in file spaces possibly cached by the OS
1421 (note: spaces of type FIL_TYPE_TEMPORARY are skipped) */
1422 void flush_file_spaces();
1423
1424 #ifndef UNIV_HOTBACKUP
1425 /** Clean up the shards. */
1426 560118 void purge() {
1427
2/2
✓ Branch 0 taken 38088024 times.
✓ Branch 1 taken 560118 times.
38648142 for (auto shard : m_shards) {
1428
1/2
✓ Branch 0 taken 38088024 times.
✗ Branch 1 not taken.
38088024 shard->purge();
1429 }
1430 560118 }
1431
1432 /** Count how many truncated undo space IDs are still tracked in
1433 the buffer pool and the file_system cache.
1434 @param[in] undo_num undo tablespace number.
1435 @return number of undo tablespaces that are still in memory. */
1436 52927 size_t count_undo_deleted(space_id_t undo_num) {
1437 52927 size_t count = 0;
1438
1439
2/2
✓ Branch 0 taken 3599036 times.
✓ Branch 1 taken 52927 times.
3651963 for (auto shard : m_shards) {
1440 3599036 count += shard->count_undo_deleted(undo_num);
1441 }
1442
1443 52927 return count;
1444 }
1445
1446 /** Check if a particular undo space_id for a page in the buffer pool has
1447 been deleted recently.
1448 Its space_id will be found in Fil_shard::m_deleted_spaces until
1449 Fil:shard::checkpoint removes the fil_space_t from Fil_system.
1450 @param[in] space_id Tablespace ID to check.
1451 @return true if this space_id is in the list of recently deleted spaces. */
1452 bool is_deleted(space_id_t space_id) noexcept {
1453 auto shard = shard_by_id(space_id);
1454
1455 return shard->is_deleted(space_id);
1456 }
1457 #endif /* !UNIV_HOTBACKUP */
1458
1459 /** Fetch the fil_space_t instance that maps to the name.
1460 @param[in] name Tablespace name to lookup
1461 @return tablespace instance or nullptr if not found. */
1462 154433 [[nodiscard]] fil_space_t *get_space_by_name(const char *name) {
1463
2/2
✓ Branch 0 taken 9434079 times.
✓ Branch 1 taken 1316 times.
9435395 for (auto shard : m_shards) {
1464
1/2
✓ Branch 0 taken 9434079 times.
✗ Branch 1 not taken.
9434079 shard->mutex_acquire();
1465
1466
1/2
✓ Branch 0 taken 9434079 times.
✗ Branch 1 not taken.
9434079 auto space = shard->get_space_by_name(name);
1467
1468
1/2
✓ Branch 0 taken 9434079 times.
✗ Branch 1 not taken.
9434079 shard->mutex_release();
1469
1470
2/2
✓ Branch 0 taken 153117 times.
✓ Branch 1 taken 9280962 times.
9434079 if (space != nullptr) {
1471 153117 return space;
1472 }
1473 }
1474
1475 1316 return nullptr;
1476 }
1477
1478 /** Check a space ID against the maximum known tablespace ID.
1479 @param[in] space_id Tablespace ID to check
1480 @return true if it is > than maximum known tablespace ID. */
1481 421744 [[nodiscard]] bool is_greater_than_max_id(space_id_t space_id) const {
1482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 421744 times.
421744 ut_ad(mutex_owned_all());
1483
1484 421744 return space_id > m_max_assigned_id;
1485 }
1486
1487 /** Update the maximum known tablespace ID.
1488 @param[in] space Tablespace instance */
1489 void set_maximum_space_id(const fil_space_t *space) {
1490 ut_ad(mutex_owned_all());
1491
1492 if (!m_space_id_reuse_warned) {
1493 m_space_id_reuse_warned = true;
1494
1495 ib::warn(ER_IB_MSG_266) << "Allocated tablespace ID " << space->id
1496 << " for " << space->name << ", old maximum"
1497 << " was " << m_max_assigned_id;
1498 }
1499
1500 m_max_assigned_id = space->id;
1501 }
1502
1503 /** Update the maximum known space ID if it's smaller than max_id.
1504 @param[in] space_id Value to set if it's greater */
1505 28614 void update_maximum_space_id(space_id_t space_id) {
1506 28614 mutex_acquire_all();
1507
1508
2/2
✓ Branch 0 taken 9416 times.
✓ Branch 1 taken 19198 times.
28614 if (is_greater_than_max_id(space_id)) {
1509 9416 m_max_assigned_id = space_id;
1510 }
1511
1512 28614 mutex_release_all();
1513 28614 }
1514
1515 /** Assigns a new space id for a new single-table tablespace. This
1516 works simply by incrementing the global counter. If 4 billion ids
1517 is not enough, we may need to recycle ids.
1518 @param[out] space_id Set this to the new tablespace ID
1519 @return true if assigned, false if not */
1520 [[nodiscard]] bool assign_new_space_id(space_id_t *space_id);
1521
1522 /** Allows other threads to advance work while we wait for I/Os to complete.
1523 */
1524 void wait_while_ios_in_progress() const {
1525 #ifndef UNIV_HOTBACKUP
1526 /* Wake the I/O-handler threads to make sure pending I/Os are
1527 performed. */
1528 os_aio_simulated_wake_handler_threads();
1529 #endif /* !UNIV_HOTBACKUP */
1530 /* Give CPU to other threads that keep files opened. */
1531 std::this_thread::sleep_for(std::chrono::milliseconds(1));
1532 }
1533
1534 /** Tries to close a file in all the LRU lists.
1535 The caller must hold the mutex.
1536 @return true if success, false if should retry later */
1537 [[nodiscard]] bool close_file_in_all_LRU();
1538
1539 /** Opens all system tablespace data files in all shards. */
1540 void open_all_system_tablespaces();
1541
1542 /** Close all open files. */
1543 void close_all_files();
1544
1545 /** Returns maximum number of allowed non-LRU files opened for a specified
1546 open files limit. */
1547 static size_t get_limit_for_non_lru_files(size_t open_files_limit);
1548
1549 /** Returns minimum open files limit to be set to allow the specified number
1550 of non-LRU files opened. This is inverse function for the
1551 get_limit_for_non_lru_files. */
1552 size_t get_minimum_limit_for_open_files(
1553 size_t n_files_not_belonging_in_lru) const;
1554
1555 /** Changes the maximum opened files limit.
1556 @param[in,out] new_max_open_files New value for the open files limit. If the
1557 limit cannot be changed, the value is changed to a minimum value recommended.
1558 If there are any concurrent calls to set_open_files_limit in progress, setting
1559 the limit will fail and the new_max_open_files will be set to 0.
1560 @return true if the new limit was set. */
1561 bool set_open_files_limit(size_t &new_max_open_files);
1562
1563 /** Returns maximum number of allowed opened files. */
1564 1619508 size_t get_open_files_limit() const { return m_open_files_limit.get_limit(); }
1565
1566 /** Iterate through all persistent tablespace files
1567 (FIL_TYPE_TABLESPACE) returning the nodes via callback function cbk.
1568 @param[in] f Callback
1569 @return any error returned by the callback function. */
1570 [[nodiscard]] dberr_t iterate(Fil_iterator::Function &f);
1571
1572 /** Rotate the tablespace keys by new master key.
1573 @return the number of tablespaces that failed to rotate. */
1574 [[nodiscard]] size_t encryption_rotate();
1575
1576 /** Reencrypt tablespace keys by current master key. */
1577 void encryption_reencrypt(std::vector<space_id_t> &sid_vector);
1578
1579 /** Detach a space object from the tablespace memory cache.
1580 Closes the tablespace files but does not delete them.
1581 There must not be any pending I/O's or flushes on the files.
1582 @param[in,out] space tablespace */
1583 void space_detach(fil_space_t *space);
1584
1585 /** @return the maximum assigned ID so far */
1586 space_id_t get_max_space_id() const { return m_max_assigned_id; }
1587
1588 /** Lookup the tablespace ID.
1589 @param[in] space_id Tablespace ID to lookup
1590 @return true if the space ID is known. */
1591 [[nodiscard]] bool lookup_for_recovery(space_id_t space_id);
1592
1593 /** Open a tablespace that has a redo log record to apply.
1594 @param[in] space_id Tablespace ID
1595 @return DB_SUCCESS if the open was successful */
1596 [[nodiscard]] dberr_t open_for_recovery(space_id_t space_id);
1597
1598 /** This function should be called after recovery has completed.
1599 Check for tablespace files for which we did not see any
1600 MLOG_FILE_DELETE or MLOG_FILE_RENAME record. These could not
1601 be recovered.
1602 @return true if there were some filenames missing for which we had to
1603 ignore redo log records during the apply phase */
1604 [[nodiscard]] bool check_missing_tablespaces();
1605
1606 /** Note that a file has been relocated.
1607 @param[in] object_id Server DD tablespace ID
1608 @param[in] space_id InnoDB tablespace ID
1609 @param[in] space_name Tablespace name
1610 @param[in] old_path Path to the old location
1611 @param[in] new_path Path scanned from disk */
1612 226 void moved(dd::Object_id object_id, space_id_t space_id,
1613 const char *space_name, const std::string &old_path,
1614 const std::string &new_path) {
1615 auto tuple =
1616
1/2
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
226 std::make_tuple(object_id, space_id, space_name, old_path, new_path);
1617
1618
2/4
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
226 m_moved.push_back(tuple);
1619 226 }
1620
1621 /** Check if a path is known to InnoDB.
1622 @param[in] path Path to check
1623 @return true if path is known to InnoDB */
1624 15110 bool check_path(const std::string &path) const {
1625 15110 return m_dirs.contains(path);
1626 }
1627
1628 /** Get the list of directories that InnoDB knows about.
1629 @return the list of directories 'dir1;dir2;....;dirN' */
1630 9693 std::string get_dirs() const { return m_dirs.get_dirs(); }
1631
1632 /** Determines if a file belongs to the least-recently-used list.
1633 @param[in] space Tablespace to check
1634 @return true if the file belongs to fil_system->m_LRU mutex. */
1635 [[nodiscard]] static bool space_belongs_in_LRU(const fil_space_t *space);
1636
1637 /** Normalize and save a directory to scan for IBD and IBU datafiles
1638 before recovery.
1639 @param[in] directory Directory to scan
1640 @param[in] is_undo_dir true for an undo directory */
1641 19433 void set_scan_dir(const std::string &directory, bool is_undo_dir) {
1642 19433 m_dirs.set_scan_dir(directory, is_undo_dir);
1643 19433 }
1644
1645 /** Normalize and save a list of directories to scan for IBD and IBU
1646 datafiles before recovery.
1647 @param[in] directories Directories to scan */
1648 86 void set_scan_dirs(const std::string &directories) {
1649 86 m_dirs.set_scan_dirs(directories);
1650 86 }
1651
1652 /** Scan the directories to build the tablespace ID to file name
1653 mapping table. */
1654 9693 dberr_t scan() { return m_dirs.scan(); }
1655
1656 /** Get the tablespace ID from an .ibd and/or an undo tablespace. If the ID is
1657 0 on the first page then try finding the ID with Datafile::find_space_id().
1658 @param[in] filename File name to check
1659 @return s_invalid_space_id if not found, otherwise the space ID */
1660 [[nodiscard]] static space_id_t get_tablespace_id(
1661 const std::string &filename);
1662
1663 /** Fil_shard by space ID.
1664 @param[in] space_id Tablespace ID
1665 @return reference to the shard */
1666 8349922787 [[nodiscard]] Fil_shard *shard_by_id(space_id_t space_id,
1667 uint *index = nullptr) const {
1668 #ifndef UNIV_HOTBACKUP
1669
2/2
✓ Branch 0 taken 3006497203 times.
✓ Branch 1 taken 5343647730 times.
8349922787 if (fsp_is_undo_tablespace(space_id)) {
1670 3006497203 const size_t limit = space_id % UNDO_SHARDS;
1671
1672
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 3006497111 times.
3006497203 if (index) *index = UNDO_SHARDS_START + limit;
1673 3006497203 return m_shards[UNDO_SHARDS_START + limit];
1674 }
1675
1676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5343916395 times.
5343647730 ut_ad(m_shards.size() == MAX_SHARDS);
1677
1678
2/2
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 5343916073 times.
5343916395 if (index) *index = space_id % UNDO_SHARDS_START;
1679 5343916395 return m_shards[space_id % UNDO_SHARDS_START];
1680 #else /* !UNIV_HOTBACKUP */
1681 ut_ad(m_shards.size() == 1);
1682
1683 return m_shards[0];
1684 #endif /* !UNIV_HOTBACKUP */
1685 }
1686
1687 3130 MY_NODISCARD Fil_shard *shard_by_index(const uint index) const {
1688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3130 times.
3130 ut_ad(index < m_shards.size());
1689 3130 return m_shards[index];
1690 }
1691
1692 3128 uint get_number_of_shards() const { return m_shards.size(); }
1693
1694 /** Acquire all the mutexes. */
1695 628392 void mutex_acquire_all() const {
1696 #ifdef UNIV_HOTBACKUP
1697 ut_ad(m_shards.size() == 1);
1698 #endif /* UNIV_HOTBACKUP */
1699
1700
2/2
✓ Branch 0 taken 42730656 times.
✓ Branch 1 taken 628392 times.
43359048 for (auto shard : m_shards) {
1701
1/2
✓ Branch 0 taken 42730656 times.
✗ Branch 1 not taken.
42730656 shard->mutex_acquire();
1702 }
1703 628392 }
1704
1705 /** Release all the mutexes. */
1706 628392 void mutex_release_all() const {
1707 #ifdef UNIV_HOTBACKUP
1708 ut_ad(m_shards.size() == 1);
1709 #endif /* UNIV_HOTBACKUP */
1710
1711
2/2
✓ Branch 0 taken 42730656 times.
✓ Branch 1 taken 628392 times.
43359048 for (auto shard : m_shards) {
1712
1/2
✓ Branch 0 taken 42730656 times.
✗ Branch 1 not taken.
42730656 shard->mutex_release();
1713 }
1714 628392 }
1715
1716 #ifdef UNIV_DEBUG
1717
1718 /** Checks the consistency of the tablespace cache.
1719 @return true if ok */
1720 [[nodiscard]] bool validate() const;
1721
1722 /** Check if all mutexes are owned
1723 @return true if all owned. */
1724 421744 [[nodiscard]] bool mutex_owned_all() const {
1725 #ifdef UNIV_HOTBACKUP
1726 ut_ad(m_shards.size() == 1);
1727 #endif /* UNIV_HOTBACKUP */
1728
1729
2/2
✓ Branch 0 taken 28678592 times.
✓ Branch 1 taken 421744 times.
29100336 for (const auto shard : m_shards) {
1730
2/4
✓ Branch 0 taken 28678592 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 28678592 times.
28678592 ut_ad(shard->mutex_owned());
1731 }
1732
1733 421744 return true;
1734 }
1735
1736 #endif /* UNIV_DEBUG */
1737
1738 /** Rename a tablespace. Use the space_id to find the shard.
1739 @param[in] space_id tablespace ID
1740 @param[in] old_name old tablespace name
1741 @param[in] new_name new tablespace name
1742 @return DB_SUCCESS on success */
1743 [[nodiscard]] dberr_t rename_tablespace_name(space_id_t space_id,
1744 const char *old_name,
1745 const char *new_name);
1746
1747 /** Free the data structures required for recovery. */
1748 9493 void free_scanned_files() { m_dirs.clear(); }
1749
1750 #ifdef UNIV_HOTBACKUP
1751 /** Extends all tablespaces to the size stored in the space header.
1752 During the mysqlbackup --apply-log phase we extended the spaces
1753 on-demand so that log records could be applied, but that may have
1754 left spaces still too small compared to the size stored in the space
1755 header. */
1756 void meb_extend_tablespaces_to_stored_len() {
1757 ut_ad(m_shards.size() == 1);
1758
1759 /* We use a single shard for MEB. */
1760 auto shard = shard_by_id(SPACE_UNKNOWN);
1761
1762 shard->mutex_acquire();
1763
1764 shard->meb_extend_tablespaces_to_stored_len();
1765
1766 shard->mutex_release();
1767 }
1768
1769 /** Process a file name passed as an input
1770 Wrapper around meb_name_process()
1771 @param[in,out] name absolute path of tablespace file
1772 @param[in] space_id The tablespace ID
1773 @param[in] deleted true if MLOG_FILE_DELETE */
1774 void meb_name_process(char *name, space_id_t space_id, bool deleted);
1775
1776 }
1777 #endif /* UNIV_HOTBACKUP */
1778
1779 private:
1780 /** Open an ibd tablespace and add it to the InnoDB data structures.
1781 This is similar to fil_ibd_open() except that it is used while
1782 processing the redo log, so the data dictionary is not available
1783 and very little validation is done. The tablespace name is extracted
1784 from the dbname/tablename.ibd portion of the filename, which assumes
1785 that the file is a file-per-table tablespace. Any name will do for
1786 now. General tablespace names will be read from the dictionary after
1787 it has been recovered. The tablespace flags are read at this time
1788 from the first page of the file in validate_for_recovery().
1789 @param[in] space_id tablespace ID
1790 @param[in] path path/to/databasename/tablename.ibd
1791 @param[out] space the tablespace, or nullptr on error
1792 @return status of the operation */
1793 [[nodiscard]] fil_load_status ibd_open_for_recovery(space_id_t space_id,
1794 const std::string &path,
1795 fil_space_t *&space);
1796
1797 private:
1798 /** Fil_shards managed */
1799 Fil_shards m_shards;
1800
1801 fil::detail::Open_files_limit m_open_files_limit;
1802
1803 /** Maximum space id in the existing tables, or assigned during
1804 the time mysqld has been up; at an InnoDB startup we scan the
1805 data dictionary and set here the maximum of the space id's of
1806 the tables there */
1807 space_id_t m_max_assigned_id;
1808
1809 /** true if fil_space_create() has issued a warning about
1810 potential space_id reuse */
1811 bool m_space_id_reuse_warned;
1812
1813 /** List of tablespaces that have been relocated. We need to
1814 update the DD when it is safe to do so. */
1815 dd_fil::Tablespaces m_moved;
1816
1817 /** Tablespace directories scanned at startup */
1818 Tablespace_dirs m_dirs;
1819
1820 /** Old file paths during 5.7 upgrade. */
1821 std::vector<std::string> m_old_paths;
1822
1823 /** Next index (modulo number of shards) to try to close a file from the LRU
1824 list to distribute closures evenly between the shards. */
1825 std::atomic_size_t m_next_shard_to_close_from_LRU{};
1826
1827 /** Current number of files that are not belonging in LRU. This includes redo
1828 and temporary tablespaces, but not files that were temporarily removed from
1829 the LRU for I/O. */
1830 std::atomic_size_t m_n_files_not_belonging_in_lru{};
1831
1832 /** Throttles messages about high files not belonging in LRU count, the
1833 warning ER_IB_WARN_MANY_NON_LRU_FILES_OPENED. */
1834 ib::Throttler m_MANY_NON_LRU_FILES_OPENED_throttler{};
1835 /** Throttles messages about long waiting for opened files limit, the warning
1836 ER_IB_MSG_TRYING_TO_OPEN_FILE_FOR_LONG_TIME. */
1837 ib::Throttler m_TRYING_TO_OPEN_FILE_FOR_LONG_TIME_throttler{};
1838 /** Throttles messages about accessing space that was already removed, the
1839 warning ACCESSING_NONEXISTINC_SPACE. */
1840 ib::Throttler m_ACCESSING_NONEXISTINC_SPACE_throttler{};
1841
1842 // Disable copying
1843 Fil_system(Fil_system &&) = delete;
1844 Fil_system(const Fil_system &) = delete;
1845 Fil_system &operator=(const Fil_system &) = delete;
1846
1847 friend class Fil_shard;
1848 };
1849
1850 /** The tablespace memory cache. This variable is nullptr before the module is
1851 initialized. */
1852 static Fil_system *fil_system = nullptr;
1853
1854 #ifdef UNIV_HOTBACKUP
1855 static ulint srv_data_read;
1856 static ulint srv_data_written;
1857 #endif /* UNIV_HOTBACKUP */
1858
1859 9986813 static bool is_fast_shutdown() {
1860 #ifndef UNIV_HOTBACKUP
1861
2/2
✓ Branch 0 taken 314542 times.
✓ Branch 1 taken 9672292 times.
10301355 return srv_shutdown_state >= SRV_SHUTDOWN_LAST_PHASE &&
1862
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 314366 times.
10301376 srv_fast_shutdown >= 2;
1863 #else
1864 return false;
1865 #endif
1866 }
1867
1868 445861 bool fil_node_t::can_be_closed() const {
1869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 445860 times.
445861 ut_ad(is_open);
1870 /* We need to wait for the pending extension and I/Os to finish. */
1871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 445860 times.
445860 if (n_pending_ios != 0) {
1872 return false;
1873 }
1874
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 445857 times.
445860 if (n_pending_flushes != 0) {
1875 3 return false;
1876 }
1877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 445857 times.
445857 if (is_being_extended) {
1878 return false;
1879 }
1880 #ifndef UNIV_HOTBACKUP
1881 /* The file must be flushed, unless we are in very fast shutdown process. */
1882
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 445681 times.
445857 if (is_fast_shutdown()) {
1883 176 return true;
1884 }
1885 #endif
1886 445681 return is_flushed();
1887 }
1888
1889 /** Replay a file rename operation if possible.
1890 @param[in] page_id Space ID and first page number in the file
1891 @param[in] old_name old file name
1892 @param[in] new_name new file name
1893 @return whether the operation was successfully applied (the name did not exist,
1894 or new_name did not exist and name was successfully renamed to new_name) */
1895 [[nodiscard]] static bool fil_op_replay_rename(const page_id_t &page_id,
1896 const std::string &old_name,
1897 const std::string &new_name);
1898
1899 #ifndef UNIV_HOTBACKUP
1900 /** Rename partition file.
1901 @param[in] old_path old file path
1902 @param[in] extn file extension suffix
1903 @param[in] revert if true, rename from new to old file
1904 @param[in] import if called during import */
1905 static void fil_rename_partition_file(const std::string &old_path,
1906 ib_file_suffix extn, bool revert,
1907 bool import);
1908 #endif /* !UNIV_HOTBACKUP */
1909
1910 /** Get modified name for partition file. During upgrade we change all
1911 partition files to have lower case separator and partition name.
1912 @param[in] old_path old file name and path
1913 @param[in] extn file extension suffix
1914 @param[out] new_path modified new name for partitioned file
1915 @return true, iff name needs modification. */
1916 static bool fil_get_partition_file(const std::string &old_path,
1917 ib_file_suffix extn, std::string &new_path);
1918
1919 #ifdef UNIV_DEBUG
1920 /** Try fil_validate() every this many times */
1921 static const size_t FIL_VALIDATE_SKIP = 17;
1922 /** Checks the consistency of the tablespace cache some of the time.
1923 @return true if ok or the check was skipped */
1924 146214876 static bool fil_validate_skip() {
1925 /** The fil_validate() call skip counter. Use a signed type
1926 because of the race condition below. */
1927 #ifdef UNIV_HOTBACKUP
1928 static meb::Mutex meb_mutex;
1929
1930 meb_mutex.lock();
1931 #endif /* UNIV_HOTBACKUP */
1932 static int fil_validate_count = FIL_VALIDATE_SKIP;
1933
1934 /* There is a race condition below, but it does not matter,
1935 because this call is only for heuristic purposes. We want to
1936 reduce the call frequency of the costly fil_validate() check
1937 in debug builds. */
1938 146214876 --fil_validate_count;
1939
1940
2/2
✓ Branch 0 taken 137621010 times.
✓ Branch 1 taken 8593866 times.
146214876 if (fil_validate_count > 0) {
1941 #ifdef UNIV_HOTBACKUP
1942 meb_mutex.unlock();
1943 #endif /* UNIV_HOTBACKUP */
1944 137621010 return true;
1945 }
1946
1947 8593866 fil_validate_count = FIL_VALIDATE_SKIP;
1948 #ifdef UNIV_HOTBACKUP
1949 meb_mutex.unlock();
1950 #endif /* UNIV_HOTBACKUP */
1951
1952 8593866 return fil_validate();
1953 }
1954
1955 /** Validate a shard */
1956 587082333 void Fil_shard::validate() const {
1957 587082333 mutex_acquire();
1958
1959 587077328 size_t n_open = 0;
1960
1961
2/2
✓ Branch 0 taken 282994094 times.
✓ Branch 1 taken 587072691 times.
870069804 for (auto elem : m_spaces) {
1962 282994457 page_no_t size = 0;
1963 282994457 auto space = elem.second;
1964
1965
2/2
✓ Branch 0 taken 282976399 times.
✓ Branch 1 taken 282986285 times.
565971119 for (const auto &file : space->files) {
1966
4/6
✓ Branch 0 taken 32200839 times.
✓ Branch 1 taken 250775448 times.
✓ Branch 2 taken 32200839 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 282976383 times.
282976287 ut_a(file.is_open || !file.n_pending_ios);
1967
1968
2/2
✓ Branch 0 taken 250776058 times.
✓ Branch 1 taken 32200325 times.
282976383 if (file.is_open) {
1969 250776058 ++n_open;
1970 }
1971
1972 282976383 size += file.size;
1973 }
1974
1975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 282992476 times.
282986285 ut_a(space->size == size);
1976 }
1977
1978
1/2
✓ Branch 0 taken 587071384 times.
✗ Branch 1 not taken.
587072691 UT_LIST_CHECK(m_LRU);
1979
1980
6/10
✓ Branch 0 taken 587071910 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 587071586 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 221337727 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 808408919 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 221337837 times.
✓ Branch 9 taken 587071082 times.
808408849 for (auto file : m_LRU) {
1981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 221337319 times.
221337849 ut_a(file->is_open);
1982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 221336125 times.
221337319 ut_a(file->n_pending_ios == 0);
1983
2/4
✓ Branch 0 taken 221337810 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 221337465 times.
221336125 ut_a(fil_system->space_belongs_in_LRU(file->space));
1984 }
1985
1986 587071082 mutex_release();
1987 587088359 }
1988
1989 /** Checks the consistency of the tablespace cache.
1990 @return true if ok */
1991 8632286 bool Fil_system::validate() const {
1992
2/2
✓ Branch 0 taken 587082535 times.
✓ Branch 1 taken 8633692 times.
595720706 for (const auto shard : m_shards) {
1993
1/2
✓ Branch 0 taken 587088420 times.
✗ Branch 1 not taken.
587083074 shard->validate();
1994 }
1995
1996 8633692 return true;
1997 }
1998 /** Checks the consistency of the tablespace cache.
1999 @return true if ok */
2000 8632290 bool fil_validate() { return fil_system->validate(); }
2001 #endif /* UNIV_DEBUG */
2002
2003 /** Constructor.
2004 @param[in] n_shards Number of shards to create
2005 @param[in] max_open Maximum number of open files */
2006 9805 Fil_system::Fil_system(size_t n_shards, size_t max_open)
2007 9805 : m_shards(),
2008
1/2
✓ Branch 0 taken 9805 times.
✗ Branch 1 not taken.
9805 m_open_files_limit(max_open),
2009 9805 m_max_assigned_id(),
2010 9805 m_space_id_reuse_warned() {
2011
2/2
✓ Branch 0 taken 666740 times.
✓ Branch 1 taken 9805 times.
676545 for (size_t i = 0; i < n_shards; ++i) {
2012
1/2
✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
666740 auto shard = ut::new_withkey<Fil_shard>(UT_NEW_THIS_FILE_PSI_KEY, i);
2013
2014
1/2
✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
666740 m_shards.push_back(shard);
2015 }
2016 9805 }
2017
2018 /** Destructor */
2019 8379 Fil_system::~Fil_system() {
2020
2/2
✓ Branch 0 taken 569772 times.
✓ Branch 1 taken 8379 times.
578151 for (auto shard : m_shards) {
2021 569772 ut::delete_(shard);
2022 }
2023
2024 8379 m_shards.clear();
2025 8379 }
2026
2027 /** Determines if a file belongs to the least-recently-used list.
2028 @param[in] space Tablespace to check
2029 @return true if the file belongs to fil_system->m_LRU mutex. */
2030 336418698 bool Fil_system::space_belongs_in_LRU(const fil_space_t *space) {
2031
2/3
✓ Branch 0 taken 239563475 times.
✓ Branch 1 taken 96859131 times.
✗ Branch 2 not taken.
336418698 switch (space->purpose) {
2032 239563475 case FIL_TYPE_TABLESPACE:
2033
2/2
✓ Branch 0 taken 237305187 times.
✓ Branch 1 taken 2258490 times.
476875211 return !fsp_is_system_tablespace(space->id) &&
2034
2/2
✓ Branch 0 taken 163406099 times.
✓ Branch 1 taken 73905637 times.
476875413 !fsp_is_undo_tablespace(space->id);
2035
2036 96859131 case FIL_TYPE_TEMPORARY:
2037 case FIL_TYPE_IMPORT:
2038 96859131 return true;
2039 }
2040
2041 ut_d(ut_error);
2042 ut_o(return false);
2043 }
2044
2045 /** Constructor
2046 @param[in] shard_id Shard ID */
2047 666740 Fil_shard::Fil_shard(size_t shard_id)
2048 666740 : m_id(shard_id),
2049 666740 m_spaces(),
2050 666740 m_names(),
2051 666740 m_LRU(),
2052 666740 m_unflushed_spaces(),
2053 666740 m_modification_counter(),
2054 666740 m_space_list(),
2055
2/4
✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 666740 times.
✗ Branch 3 not taken.
2000220 m_rotation_list() {
2056
1/2
✓ Branch 0 taken 666740 times.
✗ Branch 1 not taken.
666740 mutex_create(LATCH_ID_FIL_SHARD, &m_mutex);
2057 666740 }
2058
2059 /** Map the space ID and name to the tablespace instance.
2060 @param[in] space Tablespace instance */
2061 393130 void Fil_shard::space_add(fil_space_t *space, fil_encryption_t mode) {
2062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
393130 ut_ad(mutex_owned());
2063
2064 {
2065
1/2
✓ Branch 0 taken 393130 times.
✗ Branch 1 not taken.
393130 auto it = m_spaces.insert(Spaces::value_type(space->id, space));
2066
2067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
393130 ut_a(it.second);
2068 }
2069
2070 {
2071 393130 auto name = space->name;
2072
2073
1/2
✓ Branch 0 taken 393130 times.
✗ Branch 1 not taken.
393130 auto it = m_names.insert(Names::value_type(name, space));
2074
2075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
393130 ut_a(it.second);
2076 }
2077
2078 393130 UT_LIST_ADD_LAST(m_space_list, space);
2079
2080 /* Inform key rotation that there could be something
2081 to do */
2082
3/4
✓ Branch 0 taken 286267 times.
✓ Branch 1 taken 106863 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 286267 times.
393130 if (space->purpose == FIL_TYPE_TABLESPACE && !srv_fil_crypt_rotate_key_age &&
2083 fil_crypt_threads_event &&
2084 (mode == FIL_ENCRYPTION_ON ||
2085 (mode == FIL_ENCRYPTION_DEFAULT &&
2086 srv_default_table_encryption == DEFAULT_TABLE_ENC_ONLINE_TO_KEYRING))) {
2087 /* Key rotation is not enabled, need to inform background
2088 encryption threads. */
2089 UT_LIST_ADD_LAST(m_rotation_list, space);
2090 space->is_in_rotation_list = true;
2091 mutex_enter(&fil_crypt_threads_mutex);
2092 os_event_set(fil_crypt_threads_event);
2093 mutex_exit(&fil_crypt_threads_mutex);
2094 }
2095 393130 }
2096
2097 57259960 void Fil_shard::add_to_lru_if_needed(fil_node_t *file) {
2098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57260033 times.
57259960 ut_ad(mutex_owned());
2099
2100
2/2
✓ Branch 0 taken 19210706 times.
✓ Branch 1 taken 38049299 times.
57260033 if (Fil_system::space_belongs_in_LRU(file->space)) {
2101 19210706 UT_LIST_ADD_FIRST(m_LRU, file);
2102 }
2103 57260059 }
2104
2105 /** Remove the file node from the LRU list.
2106 @param[in,out] file File for the tablespace */
2107 57235889 void Fil_shard::remove_from_LRU(fil_node_t *file) {
2108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57236581 times.
57235889 ut_ad(mutex_owned());
2109
2110
2/2
✓ Branch 0 taken 19191724 times.
✓ Branch 1 taken 38044268 times.
57236581 if (Fil_system::space_belongs_in_LRU(file->space)) {
2111 /* The file is in the LRU list, remove it */
2112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19191723 times.
19191724 ut_ad(ut_list_exists(m_LRU, file));
2113 19191723 UT_LIST_REMOVE(m_LRU, file);
2114 }
2115 57236039 }
2116
2117 /** Close a tablespace file based on tablespace ID.
2118 @param[in] space_id Tablespace ID
2119 @return false if space_id was not found. */
2120 170096 bool Fil_shard::close_file(space_id_t space_id) {
2121 170096 mutex_acquire();
2122
2123 170096 auto space = get_space_by_id(space_id);
2124
2125
2/2
✓ Branch 0 taken 83197 times.
✓ Branch 1 taken 86899 times.
170096 if (space == nullptr) {
2126 83197 mutex_release();
2127
2128 83197 return false;
2129 }
2130
2131
2/2
✓ Branch 0 taken 86899 times.
✓ Branch 1 taken 86899 times.
173798 for (auto &file : space->files) {
2132
5/8
✓ Branch 0 taken 86443 times.
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 86443 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 86443 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 86899 times.
86899 while (file.is_open && !file.can_be_closed()) {
2133 mutex_release();
2134
2135 std::this_thread::sleep_for(std::chrono::milliseconds(10));
2136
2137 mutex_acquire();
2138 }
2139
2140
2/2
✓ Branch 0 taken 86443 times.
✓ Branch 1 taken 456 times.
86899 if (file.is_open) {
2141
1/2
✓ Branch 0 taken 86443 times.
✗ Branch 1 not taken.
86443 close_file(&file);
2142 }
2143 }
2144
2145 86899 mutex_release();
2146
2147 86899 return true;
2148 }
2149
2150 /** Remap the tablespace to the new name.
2151 @param[in] space Tablespace instance, with old name.
2152 @param[in] new_name New tablespace name */
2153 80214 void Fil_shard::update_space_name_map(fil_space_t *space,
2154 const char *new_name) {
2155
2/4
✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 80214 times.
80214 ut_ad(mutex_owned());
2156
2157
2/4
✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 80214 times.
80214 ut_ad(m_spaces.find(space->id) != m_spaces.end());
2158
2159
1/2
✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
80214 m_names.erase(space->name);
2160
2161
1/2
✓ Branch 0 taken 80214 times.
✗ Branch 1 not taken.
80214 auto it = m_names.insert(Names::value_type(new_name, space));
2162
2163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80214 times.
80214 ut_a(it.second);
2164 80214 }
2165
2166 /** Check if the basename of a filepath is an undo tablespace name
2167 @param[in] name Tablespace name
2168 @return true if it is an undo tablespace name */
2169 1835234 bool Fil_path::is_undo_tablespace_name(const std::string &name) {
2170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1835234 times.
1835234 if (name.empty()) {
2171 return false;
2172 }
2173
2174
1/2
✓ Branch 0 taken 1835234 times.
✗ Branch 1 not taken.
1835234 std::string basename = Fil_path::get_basename(name);
2175
2176 1835234 const auto end = basename.end();
2177
2178 /* 5 is the minimum length for an explicit undo space name.
2179 It must be at least this long; "_.ibu". */
2180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1835234 times.
1835234 if (basename.length() <= strlen(DOT_IBU)) {
2181 return false;
2182 }
2183
2184 /* Implicit undo names can come in two formats: undo_000 and undo000.
2185 Check for both. */
2186
2/2
✓ Branch 0 taken 289878 times.
✓ Branch 1 taken 1545356 times.
1835234 size_t u = (*(end - 4) == '_') ? 1 : 0;
2187
2188 1835234 if (basename.length() == sizeof("undo000") - 1 + u &&
2189
2/2
✓ Branch 0 taken 18772 times.
✓ Branch 1 taken 9802 times.
28574 *(end - 7 - u) == 'u' && /* 'u' */
2190
1/2
✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
18772 *(end - 6 - u) == 'n' && /* 'n' */
2191
1/2
✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
18772 *(end - 5 - u) == 'd' && /* 'd' */
2192
1/2
✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
18772 *(end - 4 - u) == 'o' && /* 'o' */
2193
1/2
✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
18772 isdigit(*(end - 3)) && /* 'n' */
2194
3/4
✓ Branch 0 taken 28574 times.
✓ Branch 1 taken 1806660 times.
✓ Branch 2 taken 18772 times.
✗ Branch 3 not taken.
1882580 isdigit(*(end - 2)) && /* 'n' */
2195
3/4
✓ Branch 0 taken 18772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18772 times.
✓ Branch 3 taken 1816462 times.
1854006 isdigit(*(end - 1))) { /* 'n' */
2196 18772 return true;
2197 }
2198
2199
3/4
✓ Branch 0 taken 1816462 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
✓ Branch 3 taken 1816198 times.
1816462 if (basename.substr(basename.length() - 4, 4) == DOT_IBU) {
2200 264 return true;
2201 }
2202
2203 1816198 return false;
2204 1835234 }
2205
2206 /** Add a space ID to filename mapping.
2207 @param[in] space_id Tablespace ID
2208 @param[in] name File name.
2209 @return number of files that map to the space ID */
2210 78701 size_t Tablespace_files::add(space_id_t space_id, const std::string &name) {
2211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78701 times.
78701 ut_a(space_id != TRX_SYS_SPACE);
2212
2213 Names *names;
2214
2215
2/2
✓ Branch 0 taken 19030 times.
✓ Branch 1 taken 59671 times.
78701 if (undo::is_reserved(space_id)) {
2216
3/6
✓ Branch 0 taken 19030 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19030 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19030 times.
19030 ut_ad(!Fil_path::has_suffix(IBD, name.c_str()));
2217
2218 /* Use m_undo_nums to allow a reserved undo space ID
2219 to be found quickly. */
2220 19030 space_id_t space_num = undo::id2num(space_id);
2221
1/2
✓ Branch 0 taken 19030 times.
✗ Branch 1 not taken.
19030 m_undo_nums[space_num] = space_id;
2222
2223
1/2
✓ Branch 0 taken 19030 times.
✗ Branch 1 not taken.
19030 names = &m_undo_paths[space_id];
2224
2225 } else {
2226
3/6
✓ Branch 0 taken 59671 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59671 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 59671 times.
59671 ut_ad(!Fil_path::has_suffix(IBU, name.c_str()));
2227
2228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59671 times.
59671 if (0 == strncmp(name.c_str(), "undo_", 5)) {
2229 ib::warn(ER_IB_MSG_267) << "Tablespace '" << name << "' naming"
2230 << " format is like an undo tablespace"
2231 << " but its ID " << space_id << " is not"
2232 << " in the undo tablespace range";
2233 }
2234
2235 59671 names = &m_ibd_paths[space_id];
2236 }
2237
2238 78701 names->push_back(name);
2239
2240 78701 return names->size();
2241 }
2242
2243 /** Reads data from a space to a buffer. Remember that the possible incomplete
2244 blocks at the end of file are ignored: they are not taken into account when
2245 calculating the byte offset within a space.
2246 @param[in] page_id page id
2247 @param[in] page_size page size
2248 @param[in] byte_offset remainder of offset in bytes; in aio this
2249 must be divisible by the OS block size
2250 @param[in] len how many bytes to read; this must not cross a
2251 file boundary; in aio this must be a block size multiple
2252 @param[in,out] buf buffer where to store data read; in aio this
2253 must be appropriately aligned
2254 @return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
2255 i/o on a tablespace which does not exist */
2256 8663 static dberr_t fil_read(const page_id_t &page_id, const page_size_t &page_size,
2257 ulint byte_offset, ulint len, void *buf) {
2258
1/2
✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
8663 return fil_io(IORequestRead, true, page_id, page_size, byte_offset, len, buf,
2259 nullptr);
2260 }
2261
2262 /** Writes data to a space from a buffer. Remember that the possible incomplete
2263 blocks at the end of file are ignored: they are not taken into account when
2264 calculating the byte offset within a space.
2265 @param[in] page_id page id
2266 @param[in] page_size page size
2267 @param[in] byte_offset remainder of offset in bytes; in aio this
2268 must be divisible by the OS block size
2269 @param[in] len how many bytes to write; this must not cross
2270 a file boundary; in aio this must be a block size multiple
2271 @param[in] buf buffer from which to write; in aio this must
2272 be appropriately aligned
2273 @return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
2274 I/O on a tablespace which does not exist */
2275 8663 static dberr_t fil_write(const page_id_t &page_id, const page_size_t &page_size,
2276 ulint byte_offset, ulint len, void *buf) {
2277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8663 times.
8663 ut_ad(!srv_read_only_mode);
2278
2279
1/2
✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
8663 return fil_io(IORequestWrite, true, page_id, page_size, byte_offset, len, buf,
2280 nullptr);
2281 }
2282
2283 /** Look up a tablespace. The caller should hold an InnoDB table lock or
2284 a MDL that prevents the tablespace from being dropped during the operation,
2285 or the caller should be in single-threaded crash recovery mode (no user
2286 connections that could drop tablespaces). If this is not the case,
2287 fil_space_acquire() and fil_space_release() should be used instead.
2288 @param[in] space_id Tablespace ID
2289 @return tablespace, or nullptr if not found */
2290 148871583 fil_space_t *fil_space_get(space_id_t space_id) {
2291 148871583 auto shard = fil_system->shard_by_id(space_id);
2292
2293 148871772 shard->mutex_acquire();
2294
2295 148871732 fil_space_t *space = shard->get_space_by_id(space_id);
2296
2297 148871549 shard->mutex_release();
2298
2299 148871906 return space;
2300 }
2301
2302 #ifndef UNIV_HOTBACKUP
2303
2304 /** Returns the latch of a file space.
2305 @param[in] space_id Tablespace ID
2306 @return latch protecting storage allocation */
2307 4280863 rw_lock_t *fil_space_get_latch(space_id_t space_id) {
2308 4280863 auto shard = fil_system->shard_by_id(space_id);
2309
2310 4280862 shard->mutex_acquire();
2311
2312 4280862 fil_space_t *space = shard->get_space_by_id(space_id);
2313
2314 4280862 shard->mutex_release();
2315
2316 4280863 return &space->latch;
2317 }
2318
2319 #ifdef UNIV_DEBUG
2320
2321 /** Gets the type of a file space.
2322 @param[in] space_id Tablespace ID
2323 @return file type */
2324 20316404 fil_type_t fil_space_get_type(space_id_t space_id) {
2325 20316404 auto shard = fil_system->shard_by_id(space_id);
2326
2327 20316403 shard->mutex_acquire();
2328
2329 20316400 auto space = shard->get_space_by_id(space_id);
2330
2331 20316399 shard->mutex_release();
2332
2333 20316404 return space->purpose;
2334 }
2335
2336 #endif /* UNIV_DEBUG */
2337
2338 524 void fil_space_set_imported(space_id_t space_id) {
2339 524 auto shard = fil_system->shard_by_id(space_id);
2340
2341 524 shard->mutex_acquire();
2342
2343 524 fil_space_t *space = shard->get_space_by_id(space_id);
2344
2345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 524 times.
524 ut_ad(space->purpose == FIL_TYPE_IMPORT);
2346 524 space->purpose = FIL_TYPE_TABLESPACE;
2347
2348 524 shard->mutex_release();
2349 524 }
2350 #endif /* !UNIV_HOTBACKUP */
2351
2352 /** Checks if all the file nodes in a space are flushed. The caller must hold
2353 the fil_system mutex.
2354 @param[in] space Tablespace to check
2355 @return true if all are flushed */
2356 8550206 bool Fil_shard::space_is_flushed(const fil_space_t *space) {
2357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8551162 times.
8550206 ut_ad(mutex_owned());
2358
2359
2/2
✓ Branch 0 taken 8551345 times.
✓ Branch 1 taken 7557517 times.
16111296 for (const auto &file : space->files) {
2360
3/4
✓ Branch 0 taken 8553895 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 993761 times.
✓ Branch 3 taken 7560134 times.
8551647 if (!file.is_flushed()) {
2361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 993756 times.
993761 ut_ad(!fil_disable_space_flushing(space));
2362 993756 return false;
2363 }
2364 }
2365
2366 7557517 return true;
2367 }
2368
2369 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
2370
2371 #include <sys/ioctl.h>
2372
2373 /** FusionIO atomic write control info */
2374 #define DFS_IOCTL_ATOMIC_WRITE_SET _IOW(0x95, 2, uint)
2375
2376 /** Try and enable FusionIO atomic writes.
2377 @param[in] file OS file handle
2378 @return true if successful */
2379 217839 bool fil_fusionio_enable_atomic_write(pfs_os_file_t file) {
2380
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 217811 times.
217839 if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
2381 28 uint atomic = 1;
2382
2383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 ut_a(file.m_file != -1);
2384
2385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (ioctl(file.m_file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic) != -1) {
2386 return true;
2387 }
2388 }
2389
2390 217839 return false;
2391 }
2392 #endif /* !NO_FALLOCATE && UNIV_LINUX */
2393
2394 /** Attach a file to a tablespace
2395 @param[in] name file name of a file that is not open
2396 @param[in] size file size in entire database blocks
2397 @param[in,out] space tablespace from fil_space_create()
2398 @param[in] is_raw whether this is a raw device or partition
2399 @param[in] punch_hole true if supported for this file
2400 @param[in] atomic_write true if the file has atomic write enabled
2401 @param[in] max_pages maximum number of pages in file
2402 @return pointer to the file name
2403 @retval nullptr if error */
2404 393161 fil_node_t *Fil_shard::create_node(const char *name, page_no_t size,
2405 fil_space_t *space, bool is_raw,
2406 bool punch_hole, bool atomic_write,
2407 page_no_t max_pages) {
2408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
393161 ut_ad(name != nullptr);
2409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
393161 ut_ad(fil_system != nullptr);
2410
2411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
393161 if (space == nullptr) {
2412 return nullptr;
2413 }
2414
2415 393161 fil_node_t file{};
2416
2417
1/2
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
393161 file.name = mem_strdup(name);
2418
2419
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 393161 times.
393161 ut_a(!is_raw || srv_start_raw_disk_in_use);
2420
2421
1/2
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
393161 file.sync_event = os_event_create();
2422
2423 393161 file.is_raw_disk = is_raw;
2424
2425 393161 file.size = size;
2426
2427 393161 file.flush_size = size;
2428
2429 393161 file.magic_n = FIL_NODE_MAGIC_N;
2430
2431 393161 file.init_size = size;
2432
2433 393161 file.max_size = max_pages;
2434
2435 393161 file.space = space;
2436
2437 393161 os_file_stat_t stat_info = os_file_stat_t();
2438
2439 #ifdef UNIV_DEBUG
2440 dberr_t err =
2441 #endif /* UNIV_DEBUG */
2442
2443 393161 os_file_get_status(
2444
1/2
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
393161 file.name, &stat_info, false,
2445
3/4
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106324 times.
✓ Branch 3 taken 286837 times.
393161 fsp_is_system_temporary(space->id) ? true : srv_read_only_mode);
2446
2447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393161 times.
393161 ut_ad(err == DB_SUCCESS);
2448
2449 393161 file.block_size = stat_info.block_size;
2450
2451 /* In this debugging mode, we can overcome the limitation of some
2452 OSes like Windows that support Punch Hole but have a hole size
2453 effectively too large. By setting the block size to be half the
2454 page size, we can bypass one of the checks that would normally
2455 turn Page Compression off. This execution mode allows compression
2456 to be tested even when full punch hole support is not available. */
2457
3/4
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 393145 times.
393161 DBUG_EXECUTE_IF(
2458 "ignore_punch_hole",
2459 file.block_size = std::min(static_cast<ulint>(stat_info.block_size),
2460 UNIV_PAGE_SIZE / 2););
2461
2462
6/8
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 393161 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 391914 times.
✓ Branch 5 taken 1247 times.
✓ Branch 6 taken 1247 times.
✓ Branch 7 taken 391914 times.
785075 if (!IORequest::is_punch_hole_supported() || !punch_hole ||
2463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 391914 times.
391914 file.block_size >= srv_page_size) {
2464
1/2
✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
1247 fil_no_punch_hole(&file);
2465 } else {
2466 391914 file.punch_hole = punch_hole;
2467 }
2468
2469 393161 file.atomic_write = atomic_write;
2470
2471
1/2
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
393161 mutex_acquire();
2472
2473 393161 space->size += size;
2474
2475
1/2
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
393161 space->files.push_back(file);
2476
2477
1/2
✓ Branch 0 taken 393161 times.
✗ Branch 1 not taken.
393161 mutex_release();
2478
2479
6/8
✓ Branch 0 taken 383444 times.
✓ Branch 1 taken 9717 times.
✓ Branch 2 taken 277120 times.
✓ Branch 3 taken 106324 times.
✓ Branch 4 taken 277120 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 393161 times.
393161 ut_a(space->id == TRX_SYS_SPACE || space->purpose == FIL_TYPE_TEMPORARY ||
2480 space->files.size() == 1);
2481
2482 393161 return &space->files.front();
2483 }
2484
2485 /** Attach a file to a tablespace. File must be closed.
2486 @param[in] name file name (file must be closed)
2487 @param[in] size file size in database blocks, rounded
2488 downwards to an integer
2489 @param[in,out] space space where to append
2490 @param[in] is_raw true if a raw device or a raw disk partition
2491 @param[in] atomic_write true if the file has atomic write enabled
2492 @param[in] max_pages maximum number of pages in file
2493 @return pointer to the file name
2494 @retval nullptr if error */
2495 35629 char *fil_node_create(const char *name, page_no_t size, fil_space_t *space,
2496 bool is_raw, bool atomic_write, page_no_t max_pages) {
2497 35629 auto shard = fil_system->shard_by_id(space->id);
2498
2499 fil_node_t *file;
2500
2501 106887 file = shard->create_node(name, size, space, is_raw,
2502 35629 IORequest::is_punch_hole_supported(), atomic_write,
2503 max_pages);
2504
2505
1/2
✓ Branch 0 taken 35629 times.
✗ Branch 1 not taken.
35629 return file == nullptr ? nullptr : file->name;
2506 }
2507
2508 59268 dberr_t Fil_shard::get_file_size(fil_node_t *file, bool read_only_mode) {
2509
2/4
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59268 times.
59268 ut_ad(mutex_owned());
2510
2511 bool success;
2512 59268 fil_space_t *space = file->space;
2513
2/4
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59268 times.
59268 ut_ad(mutex_owned());
2514
2515 do {
2516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59270 ut_a(!file->is_open);
2517
2518
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 file->handle = os_file_create_simple_no_error_handling(
2519 innodb_data_file_key, file->name, OS_FILE_OPEN, OS_FILE_READ_ONLY,
2520 read_only_mode, &success);
2521
2522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59268 if (!success) {
2523 /* The following call prints an error message */
2524 os_file_get_last_error(true);
2525
2526 ib::warn(ER_IB_MSG_268) << "Cannot open '" << file->name
2527 << "'."
2528 " Have you deleted .ibd files under a"
2529 " running mysqld server?";
2530
2531 return DB_ERROR;
2532 }
2533
2534
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 59266 times.
59268 } while (!success);
2535
2536
1/2
✓ Branch 0 taken 59266 times.
✗ Branch 1 not taken.
59266 os_offset_t size_bytes = os_file_get_size(file->handle);
2537
2538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59266 times.
59266 ut_a(size_bytes != (os_offset_t)-1);
2539
2540 #ifdef UNIV_HOTBACKUP
2541 if (space->id == TRX_SYS_SPACE) {
2542 file->size = (ulint)(size_bytes / UNIV_PAGE_SIZE);
2543 space->size += file->size;
2544 os_file_close(file->handle);
2545 return DB_SUCCESS;
2546 }
2547 #endif /* UNIV_HOTBACKUP */
2548
2549 /* Align memory for file I/O if we might have O_DIRECT set */
2550 const ulint buf_size =
2551
2/2
✓ Branch 0 taken 9528 times.
✓ Branch 1 taken 49737 times.
59266 recv_recovery_is_on() ? (UNIV_PAGE_SIZE * 2) : UNIV_PAGE_SIZE;
2552 59265 auto page = static_cast<byte *>(ut::aligned_alloc(buf_size, UNIV_PAGE_SIZE));
2553
2554
2/4
✓ Branch 0 taken 59267 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59267 times.
59268 ut_ad(page == page_align(page));
2555
2556 /* Read the first page of the tablespace */
2557
2558
1/2
✓ Branch 0 taken 59267 times.
✗ Branch 1 not taken.
59267 IORequest request(IORequest::READ);
2559
2560
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59267 dberr_t err = os_file_read_first_page(request, file->name, file->handle, page,
2561 buf_size);
2562
2563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59268 ut_a(err == DB_SUCCESS);
2564
2565
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 os_file_close(file->handle);
2566
2567
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 uint32_t flags = fsp_header_get_flags(page);
2568
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 space_id_t space_id = fsp_header_get_space_id(page);
2569
2570 /* To determine if tablespace is from 5.7 or not, we
2571 rely on SDI flag. For IBDs from 5.7, which are opened
2572 during import or during upgrade, their initial size
2573 is lesser than the initial size in 8.0 */
2574 59268 bool has_sdi = FSP_FLAGS_HAS_SDI(flags);
2575
2576
2/2
✓ Branch 0 taken 34188 times.
✓ Branch 1 taken 25080 times.
59268 uint8_t expected_size =
2577 has_sdi ? FIL_IBD_FILE_INITIAL_SIZE : FIL_IBD_FILE_INITIAL_SIZE_5_7;
2578
2579
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 const page_size_t page_size(flags);
2580
2581
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 ulint min_size = expected_size * page_size.physical();
2582
2583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59268 if (size_bytes < min_size) {
2584 if (has_sdi) {
2585 /** Add some tolerance when the tablespace is upgraded. If an empty
2586 general tablespace is created in 5.7, and then upgraded to 8.0, then
2587 its size changes from FIL_IBD_FILE_INITIAL_SIZE_5_7 pages to
2588 FIL_IBD_FILE_INITIAL_SIZE-1. */
2589
2590 ut_ad(expected_size == FIL_IBD_FILE_INITIAL_SIZE);
2591 ulint upgrade_size = (expected_size - 1) * page_size.physical();
2592
2593 if (size_bytes < upgrade_size) {
2594 ib::error(ER_IB_MSG_269)
2595 << "The size of tablespace file " << file->name << " is only "
2596 << size_bytes << ", should be at least " << upgrade_size << "!";
2597
2598 ut_error;
2599 }
2600
2601 } else {
2602 ib::error(ER_IB_MSG_269)
2603 << "The size of tablespace file " << file->name << " is only "
2604 << size_bytes << ", should be at least " << min_size << "!";
2605
2606 ut_error;
2607 }
2608 }
2609
2610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59268 if (space_id != space->id) {
2611 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_270)
2612 << "Tablespace id is " << space->id
2613 << " in the data dictionary but in file " << file->name << " it is "
2614 << space_id << "!";
2615 }
2616
2617 /* We need to adjust for compressed pages. */
2618
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 const page_size_t space_page_size(space->flags);
2619
2620
2/4
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59268 times.
59268 if (!page_size.equals_to(space_page_size)) {
2621 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_271)
2622 << "Tablespace file " << file->name << " has page size " << page_size
2623 << " (flags=" << ib::hex(flags) << ") but the data dictionary expects"
2624 << " page size " << space_page_size
2625 << " (flags=" << ib::hex(space->flags) << ")!";
2626 }
2627
2628 /* Make the SDI flag in space->flags reflect the SDI flag in the header
2629 page. Maybe this space was discarded before a reboot and then replaced
2630 with a 5.7 space that needs to be imported and upgraded. */
2631 59268 fsp_flags_unset_sdi(space->flags);
2632 59268 space->flags |= flags & FSP_FLAGS_MASK_SDI;
2633
2634 /* Data dictionary and tablespace are flushed at different points in
2635 time. If a crash happens in between, they can have different
2636 encryption flags as long as the redo log is not replayed. To avoid a
2637 recovery error due to differing encryption flags, ensure that the
2638 fil_space_t instance has the same setting as the header page. First
2639 clear the encryption flag, then set it from the flags found in the
2640 file.
2641 It is also possible that for tables, general tablespaces encryption flag
2642 is updated in DD but server crashed before encryption flag is updated on
2643 disk.
2644 Below we print warning in such case. */
2645
6/6
✓ Branch 0 taken 59265 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9525 times.
✓ Branch 3 taken 49740 times.
✓ Branch 4 taken 9525 times.
✓ Branch 5 taken 49743 times.
59268 if (space->crypt_data == nullptr && recv_recovery_is_on()) {
2646 9525 fsp_flags_unset_encryption(space->flags);
2647 9525 space->flags |= flags & FSP_FLAGS_MASK_ENCRYPTION;
2648 }
2649
2650 /* Make a copy of space->flags and flags from the page header
2651 so that they can be compared. */
2652 /* Do not compare the data directory flag, in case this tablespace was
2653 relocated. */
2654 59268 auto fil_space_flags = space->flags & ~FSP_FLAGS_MASK_DATA_DIR;
2655 59268 auto header_fsp_flags = flags & ~FSP_FLAGS_MASK_DATA_DIR;
2656
2657 // in case of Keyring encryption it can so happen that there will be a crash
2658 // after all pages of tablespace is rotated and DD is updated, but page0 of
2659 // the tablespace has not been yet update. We handle this here.
2660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (space->crypt_data != nullptr &&
2661 3 ((FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) &&
2662
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 space->crypt_data->min_key_version == 0) ||
2663 3 (!FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) &&
2664
4/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59265 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 59268 times.
59271 space->crypt_data->min_key_version != 0)) &&
2665 FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) !=
2666 FSP_FLAGS_GET_ENCRYPTION(header_fsp_flags)) {
2667 if (srv_n_fil_crypt_threads_requested == 0) {
2668 ib::warn() << "Table encryption flag is "
2669 << (FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) ? "ON" : "OFF")
2670 << " in the data dictionary but the encryption flag in file "
2671 << file->name << " is "
2672 << (FSP_FLAGS_GET_ENCRYPTION(header_fsp_flags) ? "ON" : "OFF")
2673 << ". This indicates that the rotation of the table was "
2674 "interrupted before space's flags were updated."
2675 << " Please have encryption_thread variable "
2676 "(innodb-encryption-threads) set to value > 0. So the "
2677 "encryption"
2678 << " could finish up the rotation.";
2679 }
2680 // exclude encryption flag from validation
2681 fsp_flags_unset_encryption(fil_space_flags);
2682 fsp_flags_unset_encryption(header_fsp_flags);
2683 }
2684
2685 /* Make sure the space_flags are the same as the header page flags. */
2686
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59268 if (UNIV_UNLIKELY(fil_space_flags != header_fsp_flags)) {
2687 ib::error(ER_IB_MSG_272, ulong{space->flags}, file->name, ulonglong{flags});
2688 ut_error;
2689 }
2690
2691 {
2692
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 page_no_t size = fsp_header_get_field(page, FSP_SIZE);
2693
2694 page_no_t free_limit;
2695
2696
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT);
2697
2698 ulint free_len;
2699
2700
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59268 free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + page);
2701
2702
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 59268 times.
59268 ut_ad(space->free_limit == 0 || space->free_limit == free_limit);
2703
2704
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 59268 times.
59268 ut_ad(space->free_len == 0 || space->free_len == free_len);
2705
2706 59268 space->size_in_header = size;
2707 59268 space->free_limit = free_limit;
2708
2709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59268 ut_a(free_len < std::numeric_limits<uint32_t>::max());
2710
2711 59268 space->free_len = (uint32_t)free_len;
2712
2713 /* TODO: Get consistent flag from recovered DD. For that, DD should be
2714 recovered already. */
2715 /* Set estimated value for space->compression_type
2716 during recovery process. */
2717
2718
4/4
✓ Branch 0 taken 9528 times.
✓ Branch 1 taken 49740 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 59244 times.
68796 if (recv_recovery_is_on() &&
2719
4/6
✓ Branch 0 taken 9528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9528 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9512 times.
✓ Branch 5 taken 16 times.
9528 (Compression::is_compressed_page(page + page_size.physical()) ||
2720
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9504 times.
9512 Compression::is_compressed_encrypted_page(page +
2721
2/4
✓ Branch 0 taken 9512 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9512 times.
✗ Branch 3 not taken.
9512 page_size.physical()))) {
2722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 ut_ad(buf_size >= (UNIV_PAGE_SIZE * 2));
2723 Compression::meta_t header;
2724
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 Compression::deserialize_header(page + page_size.physical(), &header);
2725 24 space->compression_type = header.m_algorithm;
2726 }
2727 }
2728
2729 59268 ut::aligned_free(page);
2730
2731 /* For encrypted tablespace, we need to check the
2732 encryption key and iv(initial vector) is read. */
2733
5/6
✓ Branch 0 taken 636 times.
✓ Branch 1 taken 58632 times.
✓ Branch 2 taken 424 times.
✓ Branch 3 taken 212 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 59268 times.
59692 if (FSP_FLAGS_GET_ENCRYPTION(space->flags) && !recv_recovery_is_on() &&
2734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 424 times.
424 space->m_encryption_metadata.m_type != Encryption::AES) {
2735 ib::error(ER_IB_MSG_273, file->name);
2736
2737 return DB_ERROR;
2738 }
2739
2740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (space->crypt_data && space->crypt_data->type == CRYPT_SCHEME_1 &&
2741
3/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59265 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 59268 times.
59271 !space->crypt_data->key_found && !recv_recovery_is_on()) {
2742 ib::error() << "There is no key for tablespace " << space->name;
2743 return (DB_IO_DECRYPT_FAIL);
2744 }
2745
2746
2/2
✓ Branch 0 taken 34342 times.
✓ Branch 1 taken 24926 times.
59268 if (file->size == 0) {
2747 ulint extent_size;
2748
2749
2/6
✓ Branch 0 taken 34342 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34342 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
34342 extent_size = page_size.physical() * FSP_EXTENT_SIZE;
2750
2751 #ifndef UNIV_HOTBACKUP
2752 /* Truncate the size to a multiple of extent size. */
2753
2/2
✓ Branch 0 taken 14208 times.
✓ Branch 1 taken 20134 times.
34342 if (size_bytes >= extent_size) {
2754 14208 size_bytes = ut_2pow_round(size_bytes, extent_size);
2755 }
2756 #else /* !UNIV_HOTBACKUP */
2757
2758 /* After apply-incremental, tablespaces are not
2759 extended to a whole megabyte. Do not cut off
2760 valid data. */
2761
2762 #endif /* !UNIV_HOTBACKUP */
2763
2764
1/2
✓ Branch 0 taken 34342 times.
✗ Branch 1 not taken.
34342 file->size = static_cast<page_no_t>(size_bytes / page_size.physical());
2765
2766 34342 space->size += file->size;
2767 }
2768
2769 59268 return DB_SUCCESS;
2770 59268 }
2771
2772 35221 size_t Fil_system::get_limit_for_non_lru_files(size_t open_files_limit) {
2773 /* Leave at least 10% of the limit for the LRU files, to not make system too
2774 inefficient in an edge case there is a lot of non-LRU files causing LRU
2775 ones to be constantly closed and opened. The absolute minimum would be a
2776 single slot for LRU files, but it may be very inefficient. Let's make two the
2777 hard limit. */
2778 const size_t minimum_limit_left_for_lru_files =
2779 35221 std::max(2LL, std::llround(0.1 * open_files_limit));
2780 35221 return open_files_limit - minimum_limit_left_for_lru_files;
2781 }
2782
2783 28 size_t Fil_system::get_minimum_limit_for_open_files(
2784 size_t n_files_not_belonging_in_lru) const {
2785 28 size_t result = 0;
2786 /* Start with the most significant bit and iterate till last one. */
2787 28 for (size_t current_bit = ~(std::numeric_limits<size_t>::max() >> 1);
2788
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 28 times.
1820 current_bit; current_bit >>= 1) {
2789
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 1704 times.
1792 if (get_limit_for_non_lru_files(result + current_bit - 1) <
2790 n_files_not_belonging_in_lru) {
2791 88 result += current_bit;
2792 }
2793 }
2794
2795 28 return result;
2796 }
2797
2798 306702 bool Fil_shard::open_file(fil_node_t *file) {
2799 bool success;
2800 306702 fil_space_t *space = file->space;
2801
2802
2/4
✓ Branch 0 taken 306704 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 306704 times.
306702 ut_ad(mutex_owned());
2803
2804 /* This method is not straightforward. The description is included in comments
2805 to different parts of this function. They are best read one after another
2806 in order. */
2807
2808
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306703 times.
306704 ut_a(!file->is_open);
2809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306703 times.
306703 ut_a(file->n_pending_ios == 0);
2810
2811 306703 const auto start_time = std::chrono::steady_clock::now();
2812
2813 /* This method first assures we can open a file. This comes down to assuring a
2814 correct state under locks is present and that opening of this file will not
2815 exceed any limits. Currently we have two limits for open files:
2816 - maximum number of opened files - fil_system->m_open_files_limit,
2817 - maximum number of opened files that can't be closed on request, i.e. are not
2818 part of open files LRU list.
2819
2820 We can ignore the latter iff the file will be part of the LRU.
2821 For each limit we need to comply with, we need to bump the current number of
2822 files within the limit. If the bump succeeds (results in a current number not
2823 larger than the limit value), we have a right to open a file.
2824
2825 When all rights are acquired the `Fil_shard::open_file` opens the file and
2826 returns true. The file opened will naturally count against the limits. After
2827 this happens, the current values of files for the limits are decreased only in
2828 `Fil_shard::close_file`. */
2829
2830 /* We remember if we have already acquired right to open the file against the
2831 total open files limit. */
2832 306701 bool have_right_for_open = false;
2833 /* As well as the right to open the file against limit for files that do not
2834 take part in LRU algorithm. If the file takes part in LRU algorithm, this
2835 is never true. */
2836 306701 bool have_right_for_open_non_lru = false;
2837
2838 /* To acquire a right against a limit, we use this helper function. It
2839 atomically tries to bump the value of supplied reference to a current value
2840 as long as it is below the limit set. Returns true if the right to open is
2841 acquired. */
2842 345418 const auto acquire_right = [](std::atomic<size_t> &counter,
2843 size_t limit) -> bool {
2844 345418 auto current_count = counter.load();
2845
2/2
✓ Branch 0 taken 340133 times.
✓ Branch 1 taken 5300 times.
345433 while (limit > current_count) {
2846
2/2
✓ Branch 0 taken 340129 times.
✓ Branch 1 taken 10 times.
680272 if (counter.compare_exchange_weak(current_count, current_count + 1)) {
2847 340129 return true;
2848 }
2849 }
2850 5300 return false;
2851 };
2852
2853 /* At any point we can decide to release any rights that we have acquired so
2854 far. This will make us unable to open the file now. The
2855 `Fil_shard::open_file()` when returning `false` must assure no rights are
2856 left unreleased - this helper function helps to assure that. */
2857 6 const auto release_rights = [&]() {
2858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (have_right_for_open) {
2859 fil_n_files_open.fetch_sub(1);
2860 have_right_for_open = false;
2861 }
2862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (have_right_for_open_non_lru) {
2863 ut_ad(fil_system->m_n_files_not_belonging_in_lru.load() > 0);
2864 fil_system->m_n_files_not_belonging_in_lru.fetch_sub(1);
2865 have_right_for_open_non_lru = false;
2866 }
2867 306707 };
2868
2869 /* Helper function: In case of repeated errors, we will delay printing of
2870 any messages to log by PRINT_INTERVAL_SECS after the method processing
2871 starts and then print one message per PRINT_INTERVAL_SECS. */
2872 const auto should_print_message =
2873 10604 [&start_time](ib::Throttler &throttler) -> bool {
2874 5302 const auto current_time = std::chrono::steady_clock::now();
2875
3/6
✓ Branch 0 taken 5302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5302 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5302 times.
5302 if (current_time - start_time >= PRINT_INTERVAL) {
2876 return throttler.apply();
2877 }
2878 5302 return false;
2879 306701 };
2880 /* If this is `false`, the file to open will count against the limit for
2881 opened files not taking part in the LRU algorithm. We will need to acquire
2882 a right to open it. */
2883
1/2
✓ Branch 0 taken 306704 times.
✗ Branch 1 not taken.
306701 const bool belongs_to_lru = Fil_system::space_belongs_in_LRU(file->space);
2884
2885 /* We remember the current limit for opened files. If it changes while we are
2886 acquiring the rights, we must ensure we have not caused it to be bumped higher
2887 than the new limit. This double checking works together with double checking
2888 in the `Fil_system::set_open_files_limit` to ensure no race conditions are
2889 possible to leave number of opened files over the limit even in an event of
2890 changing the limit in parallel.
2891
2892 The non-LRU files limit can only change when the main limit for open files is
2893 changed, so we monitor only the main one. */
2894 306704 auto last_open_file_limit = fil_system->get_open_files_limit();
2895
2896 /* This is the main loop. It tries to assure all conditions required to open
2897 the file or causes `open_file` to exit if the file is already opened in
2898 different thread.
2899
2900 At this point, start of each loop and upon exit of the loop (either with
2901 `break` or `return`) the shard's mutex is owned by this thread. However, it
2902 may be released and re-acquired in meantime, for a while, inside this loop. If
2903 we decide to release the mutex, we must execute the loop from begin after
2904 re-acquiring it.
2905
2906 The following is the list of conditions we must fulfill to allow file to be
2907 opened:
2908 1. At any point, if the file becomes open, we just return success. Must be
2909 done under the mutex.
2910
2911 2. At any point, if the space becomes deleted, we just return failure. Must be
2912 done under the mutex.
2913
2914 3. If the file is locked with `space->prevent_file_open`, then release any
2915 rights against the limits acquired so far, and wait till the "lock" is
2916 released. The check must be done under the mutex. But the waiting must be
2917 executed only when we don't own the mutex - it is required by other thread to
2918 release the "lock".
2919
2920 4. Reserve a right within the non-LRU opened files limit. This is conditional
2921 - required only if the file is supposed to not be placed in the opened files
2922 LRU. This is lock-free.
2923
2924 5. Reserve a right within the fil_system->get_open_files_limit(),
2925 unconditionally.
2926
2927 6. Check if the limit value for the opened files have not changed. If it did,
2928 we just release all rights and retry from the beginning.
2929
2930 7. Only then we can proceed with actually opening the file. */
2931 for (;;) {
2932 /* 1. If the file becomes open, we just return success. We own the mutex,
2933 may have some rights already acquired. */
2934
2/4
✓ Branch 0 taken 312002 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 312004 times.
312001 ut_ad(mutex_owned());
2935
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 312000 times.
312004 if (file->is_open) {
2936
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 release_rights();
2937 4 return true;
2938 }
2939
2940 /* 2. If the space becomes deleted, we just return failure. We own the
2941 mutex and may have some rights already acquired.*/
2942
2/4
✓ Branch 0 taken 311998 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 311998 times.
312000 if (space->is_deleted()) {
2943 release_rights();
2944 return false;
2945 }
2946
2947 /* 3. If the file is locked with `space->prevent_file_open`. */
2948
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 311996 times.
311998 if (space->prevent_file_open) {
2949 /* Someone wants to rename the file. We can't have it opened now.
2950 Give CPU to other thread that renames the file. Release any
2951 rights and the mutex before we go to sleep - we will not need it and
2952 someone else will be able to get these or use the mutex to change the
2953 `space->prevent_file_open`. */
2954
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_release();
2955
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 release_rights();
2956
2957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (should_print_message(
2958
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 space->m_prevent_file_open_wait_message_throttler)) {
2959 ib::warn(ER_IB_MSG_278, space->name,
2960 (long long)std::chrono::duration_cast<std::chrono::seconds>(
2961 std::chrono::steady_clock::now() - start_time)
2962 .count());
2963 }
2964
2965 #ifndef UNIV_HOTBACKUP
2966 /* Wake the I/O handler threads to make sure pending I/O's are performed
2967 */
2968
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 os_aio_simulated_wake_handler_threads();
2969
2970 #endif /* UNIV_HOTBACKUP */
2971
2972
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 std::this_thread::sleep_for(std::chrono::milliseconds(1));
2973
2974
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_acquire();
2975 2 continue;
2976 }
2977 /* 4. We try to acquire required right for non-LRU file, if it is not taking
2978 part in the LRU algorithm. */
2979
3/4
✓ Branch 0 taken 33429 times.
✓ Branch 1 taken 278567 times.
✓ Branch 2 taken 33429 times.
✗ Branch 3 not taken.
311996 if (!(belongs_to_lru || have_right_for_open_non_lru)) {
2980 33429 have_right_for_open_non_lru =
2981
1/2
✓ Branch 0 taken 33429 times.
✗ Branch 1 not taken.
33429 acquire_right(fil_system->m_n_files_not_belonging_in_lru,
2982 Fil_system::get_limit_for_non_lru_files(
2983 fil_system->get_open_files_limit()));
2984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33429 times.
33429 if (!have_right_for_open_non_lru) {
2985 mutex_release();
2986 if (should_print_message(
2987 fil_system->m_MANY_NON_LRU_FILES_OPENED_throttler)) {
2988 ib::warn(ER_IB_WARN_MANY_NON_LRU_FILES_OPENED,
2989 fil_system->m_n_files_not_belonging_in_lru.load(),
2990 fil_system->get_open_files_limit());
2991 }
2992 /* Give CPU to other threads that keep files opened. */
2993 std::this_thread::sleep_for(std::chrono::milliseconds(1));
2994 mutex_acquire();
2995 continue;
2996 }
2997 }
2998
2999 /* 5. We try to acquire required right to open file. */
3000
2/2
✓ Branch 0 taken 311991 times.
✓ Branch 1 taken 5 times.
311996 if (!have_right_for_open) {
3001 312000 have_right_for_open =
3002 311991 acquire_right(fil_n_files_open, fil_system->get_open_files_limit());
3003
2/2
✓ Branch 0 taken 5300 times.
✓ Branch 1 taken 306700 times.
312000 if (!have_right_for_open) {
3004
1/2
✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
5300 mutex_release();
3005
3006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5300 times.
5300 if (should_print_message(
3007
1/2
✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
5300 fil_system->m_TRYING_TO_OPEN_FILE_FOR_LONG_TIME_throttler)) {
3008 ib::warn warning(
3009 ER_IB_MSG_TRYING_TO_OPEN_FILE_FOR_LONG_TIME,
3010 static_cast<long long>(
3011 std::chrono::duration_cast<std::chrono::seconds>(
3012 std::chrono::steady_clock::now() - start_time)
3013 .count()),
3014 fil_system->get_open_files_limit());
3015 }
3016
3017 /* Flush tablespaces so that we can close modified files in the LRU
3018 list. */
3019
1/2
✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
5300 fil_system->flush_file_spaces();
3020
3021
2/4
✓ Branch 0 taken 5300 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5300 times.
5300 if (!fil_system->close_file_in_all_LRU()) {
3022 fil_system->wait_while_ios_in_progress();
3023 }
3024
1/2
✓ Branch 0 taken 5296 times.
✗ Branch 1 not taken.
5300 mutex_acquire();
3025 5296 continue;
3026 5296 }
3027 }
3028
3029 /* 6. Re-check the open files limit value. This is working in tandem with
3030 double checking the limits in the `set_open_files_limit()`. Either this
3031 thread or one executing `set_open_files_limit()` will spot the limit is
3032 exceeded and rollback to a correct state: either restore limit or release
3033 rights. */
3034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306700 times.
306705 if (last_open_file_limit != fil_system->get_open_files_limit()) {
3035 release_rights();
3036 last_open_file_limit = fil_system->get_open_files_limit();
3037 continue;
3038 }
3039 /* 7. If we have all required rights, and checked under the mutex the
3040 file is not open and can be opened, proceed to opening the file. The file
3041 must be opened before we release the mutex again. */
3042 306700 break;
3043 5298 }
3044
3045 /* We have fulfilled all requirements to actually open the file. */
3046
2/4
✓ Branch 0 taken 306700 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 306700 times.
306700 ut_ad(mutex_owned());
3047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306700 times.
306700 ut_ad(!file->is_open);
3048
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 306696 times.
306700 ut_ad(!space->prevent_file_open);
3049
4/6
✓ Branch 0 taken 33429 times.
✓ Branch 1 taken 273267 times.
✓ Branch 2 taken 33429 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 306696 times.
306696 ut_ad(belongs_to_lru || have_right_for_open_non_lru);
3050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306694 times.
306696 ut_ad(have_right_for_open);
3051
3052 bool read_only_mode;
3053
3054
5/6
✓ Branch 0 taken 306699 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198134 times.
✓ Branch 3 taken 108565 times.
✓ Branch 4 taken 245 times.
✓ Branch 5 taken 197889 times.
306694 read_only_mode = !fsp_is_system_temporary(space->id) && srv_read_only_mode;
3055
3056
4/4
✓ Branch 0 taken 272356 times.
✓ Branch 1 taken 34343 times.
✓ Branch 2 taken 59266 times.
✓ Branch 3 taken 247429 times.
579051 if (file->size == 0 ||
3057
5/6
✓ Branch 0 taken 34551 times.
✓ Branch 1 taken 237805 times.
✓ Branch 2 taken 24927 times.
✓ Branch 3 taken 9624 times.
✓ Branch 4 taken 24931 times.
✗ Branch 5 not taken.
297283 (space->size_in_header == 0 && space->purpose == FIL_TYPE_TABLESPACE &&
3058 24927 file == &space->files.front()
3059 #ifndef UNIV_HOTBACKUP
3060
4/6
✓ Branch 0 taken 24927 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24927 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24923 times.
✓ Branch 5 taken 4 times.
24931 && undo::is_active(space->id, false) &&
3061 srv_startup_is_before_trx_rollback_phase
3062 #endif /* !UNIV_HOTBACKUP */
3063 )) {
3064 /* We don't know the file size yet. */
3065
1/2
✓ Branch 0 taken 59268 times.
✗ Branch 1 not taken.
59266 dberr_t err = get_file_size(file, read_only_mode);
3066
3067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59268 times.
59268 if (err != DB_SUCCESS) {
3068 /* Release the rights acquired as we failed to open it in the end.
3069 */
3070 release_rights();
3071 return false;
3072 }
3073 }
3074
3075 /* Open the file for reading and writing, in Windows normally in the
3076 unbuffered async I/O mode, though global variables may make os_file_create()
3077 to fall back to the normal file I/O mode. */
3078
3079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306697 times.
306697 if (file->is_raw_disk) {
3080 file->handle =
3081 os_file_create(innodb_data_file_key, file->name, OS_FILE_OPEN_RAW,
3082 OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success);
3083 } else {
3084 file->handle =
3085
1/2
✓ Branch 0 taken 306697 times.
✗ Branch 1 not taken.
306697 os_file_create(innodb_data_file_key, file->name, OS_FILE_OPEN,
3086 OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success);
3087 }
3088
3089
1/2
✓ Branch 0 taken 306697 times.
✗ Branch 1 not taken.
306697 if (success) {
3090
1/2
✓ Branch 0 taken 306700 times.
✗ Branch 1 not taken.
306697 add_to_lru_if_needed(file);
3091 /* The file is ready for IO. */
3092 306700 file->is_open = true;
3093 } else {
3094 /* Release the rights acquired as we failed to open it in the end. */
3095 release_rights();
3096 }
3097
3098 /* We exit with the mutex acquired. The file is assured to remain open only as
3099 long as the mutex is held. Calls, like to `prepare_file_for_io()` are
3100 required to continue to use the file with the mutex released. */
3101 306700 return success;
3102 }
3103
3104 283613 void Fil_shard::close_file(fil_node_t *file) {
3105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283615 times.
283613 ut_ad(mutex_owned());
3106
3107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283615 times.
283615 ut_a(file->can_be_closed());
3108
3109 283615 bool ret = os_file_close(file->handle);
3110
3111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283614 times.
283614 ut_a(ret);
3112
3113 283614 file->handle.m_file = (os_file_t)-1;
3114
3115 283614 file->is_open = false;
3116
3117 283614 auto old_files_open_count = fil_n_files_open.fetch_sub(1);
3118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283615 times.
283614 ut_a(old_files_open_count > 0);
3119
3120
2/2
✓ Branch 0 taken 29339 times.
✓ Branch 1 taken 254274 times.
283615 if (!Fil_system::space_belongs_in_LRU(file->space)) {
3121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29339 times.
58678 ut_ad(fil_system->m_n_files_not_belonging_in_lru.load() > 0);
3122
3123 29339 fil_system->m_n_files_not_belonging_in_lru.fetch_sub(1);
3124 }
3125
3126 283613 remove_from_LRU(file);
3127 283615 }
3128
3129 20856 bool Fil_shard::close_files_in_LRU() {
3130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20854 times.
20856 ut_ad(mutex_owned());
3131
3132
2/2
✓ Branch 0 taken 5327 times.
✓ Branch 1 taken 15529 times.
20856 for (auto file = UT_LIST_GET_LAST(m_LRU); file != nullptr;
3133 2 file = UT_LIST_GET_PREV(LRU, file)) {
3134
2/2
✓ Branch 0 taken 5324 times.
✓ Branch 1 taken 2 times.
5327 if (file->can_be_closed()) {
3135 5324 close_file(file);
3136
3137 5325 return true;
3138 }
3139 }
3140
3141 15529 return false;
3142 }
3143
3144 5325 bool Fil_system::close_file_in_all_LRU() {
3145 5325 const auto n_shards = m_shards.size();
3146 5325 const auto index = m_next_shard_to_close_from_LRU++;
3147
1/2
✓ Branch 0 taken 20858 times.
✗ Branch 1 not taken.
20858 for (size_t i = 0; i < n_shards; ++i) {
3148 20858 auto shard = m_shards[(index + i) % n_shards];
3149 20858 shard->mutex_acquire();
3150
3151 20856 bool success = shard->close_files_in_LRU();
3152
3153 20856 shard->mutex_release();
3154
3155
2/2
✓ Branch 0 taken 5325 times.
✓ Branch 1 taken 15534 times.
20859 if (success) {
3156 5325 return true;
3157 }
3158 }
3159
3160 return false;
3161 }
3162
3163 1405289891 fil_space_t *Fil_shard::get_space_by_id(space_id_t space_id) const {
3164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1405292066 times.
1405289891 ut_ad(mutex_owned());
3165
3166
2/2
✓ Branch 0 taken 13370529 times.
✓ Branch 1 taken 1391921537 times.
1405292066 if (space_id == TRX_SYS_SPACE) {
3167 13370529 return fil_space_t::s_sys_space;
3168 }
3169
3170 1391921537 return get_space_by_id_from_map(space_id);
3171 }
3172
3173 /** Prepare to free a file. Remove from the unflushed list if there
3174 are no pending flushes.
3175 @param[in,out] file File instance to free */
3176 81490 void Fil_shard::prepare_to_free_file(fil_node_t *file) {
3177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81490 times.
81490 ut_ad(mutex_owned());
3178
3179 81490 fil_space_t *space = file->space;
3180
3181
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 81490 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 81490 times.
81490 if (space->is_in_unflushed_spaces && space_is_flushed(space)) {
3182 space->is_in_unflushed_spaces = false;
3183
3184 UT_LIST_REMOVE(m_unflushed_spaces, space);
3185 }
3186 81490 }
3187
3188 /** Prepare to free a file object from a tablespace memory cache.
3189 @param[in,out] file Tablespace file
3190 @param[in] space tablespace */
3191 361998 void Fil_shard::file_close_to_free(fil_node_t *file, fil_space_t *space) {
3192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
361998 ut_ad(mutex_owned());
3193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
361998 ut_a(file->magic_n == FIL_NODE_MAGIC_N);
3194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
361998 ut_a(file->n_pending_ios == 0);
3195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
361998 ut_a(!file->is_being_extended);
3196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361998 times.
361998 ut_a(file->space == space);
3197
3198
2/2
✓ Branch 0 taken 81490 times.
✓ Branch 1 taken 280508 times.
361998 if (file->is_open) {
3199 /* We fool the assertion in Fil_system::close_file() to think
3200 there are no unflushed modifications in the file */
3201
3202 81490 file->set_flushed();
3203
3204 81490 os_event_set(file->sync_event);
3205
3206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81490 times.
81490 if (fil_disable_space_flushing(space)) {
3207 ut_ad(!space->is_in_unflushed_spaces);
3208 ut_ad(space_is_flushed(space));
3209
3210 } else {
3211 81490 prepare_to_free_file(file);
3212 }
3213
3214 81490 close_file(file);
3215 }
3216 361998 }
3217
3218 361970 void Fil_shard::space_detach(fil_space_t *space) {
3219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
361970 ut_ad(mutex_owned());
3220
3221 361970 m_names.erase(space->name);
3222
3223
2/2
✓ Branch 0 taken 817 times.
✓ Branch 1 taken 361153 times.
361970 if (space->is_in_unflushed_spaces) {
3224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 817 times.
817 ut_ad(!fil_disable_space_flushing(space));
3225
3226 817 space->is_in_unflushed_spaces = false;
3227
3228 817 UT_LIST_REMOVE(m_unflushed_spaces, space);
3229 }
3230
3231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
361970 if (space->is_in_rotation_list) {
3232 UT_LIST_REMOVE(m_rotation_list, space);
3233 space->is_in_rotation_list = false;
3234 }
3235
3236 361970 UT_LIST_REMOVE(m_space_list, space);
3237
3238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
361970 ut_a(space->magic_n == FIL_SPACE_MAGIC_N);
3239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 361970 times.
361970 ut_a(space->n_pending_flushes == 0);
3240
3241
2/2
✓ Branch 0 taken 361998 times.
✓ Branch 1 taken 361970 times.
723968 for (auto &file : space->files) {
3242
1/2
✓ Branch 0 taken 361998 times.
✗ Branch 1 not taken.
361998 file_close_to_free(&file, space);
3243 }
3244 361970 }
3245
3246 /** Free a tablespace object on which fil_space_detach() was invoked.
3247 There must not be any pending I/O's or flushes on the files.
3248 @param[in,out] space tablespace */
3249 360122 void Fil_shard::space_free_low(fil_space_t *&space) {
3250 /* Wait for fil_space_t::release_for_io(); */
3251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360122 times.
360122 while (space->n_pending_ios) {
3252 std::this_thread::sleep_for(std::chrono::microseconds(100));
3253 }
3254
3255 #ifndef UNIV_HOTBACKUP
3256 {
3257 /* Temporary and undo tablespaces IDs are assigned from a large but
3258 fixed size pool of reserved IDs. Therefore we must ensure that a
3259 fil_space_t instance can't be dropped until all the pages that point
3260 to it are also purged from the buffer pool. */
3261
3262
4/6
✓ Branch 0 taken 181544 times.
✓ Branch 1 taken 178578 times.
✓ Branch 2 taken 181544 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 360122 times.
360122 ut_a(srv_shutdown_state.load() == SRV_SHUTDOWN_LAST_PHASE ||
3263 space->has_no_references());
3264 }
3265 #endif /* !UNIV_HOTBACKUP */
3266
3267
2/2
✓ Branch 0 taken 360150 times.
✓ Branch 1 taken 360122 times.
720272 for (auto &file : space->files) {
3268 360150 ut_d(space->size -= file.size);
3269
3270
1/2
✓ Branch 0 taken 360150 times.
✗ Branch 1 not taken.
360150 os_event_destroy(file.sync_event);
3271
3272 360150 ut::free(file.name);
3273 }
3274
3275 360122 call_destructor(&space->files);
3276
3277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360122 times.
360122 ut_ad(space->size == 0);
3278
3279 360122 rw_lock_free(&space->latch);
3280
3281 360122 fil_space_destroy_crypt_data(&space->crypt_data);
3282
3283 360122 ut::free(space->name);
3284 360122 ut::free(space);
3285
3286 360122 space = nullptr;
3287 360122 }
3288
3289 /** Frees a space object from the tablespace memory cache.
3290 Closes a tablespaces' files but does not delete them.
3291 There must not be any pending I/O's or flushes on the files.
3292 @param[in] space_id Tablespace ID
3293 @return fil_space_t instance on success or nullptr */
3294 2 fil_space_t *Fil_shard::space_free(space_id_t space_id) {
3295 2 mutex_acquire();
3296
3297 2 fil_space_t *space = get_space_by_id(space_id);
3298
3299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (space != nullptr) {
3300 space_detach(space);
3301
3302 space_remove_from_lookup_maps(space_id);
3303 }
3304
3305 2 mutex_release();
3306
3307 2 return space;
3308 }
3309
3310 /** Frees a space object from the tablespace memory cache.
3311 Closes a tablespaces' files but does not delete them.
3312 There must not be any pending i/o's or flushes on the files.
3313 @param[in] space_id Tablespace ID
3314 @param[in] x_latched Whether the caller holds X-mode space->latch
3315 @return true if success */
3316 2 static bool fil_space_free(space_id_t space_id, bool x_latched) {
3317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ut_ad(space_id != TRX_SYS_SPACE);
3318
3319
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 auto shard = fil_system->shard_by_id(space_id);
3320
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 auto space = shard->space_free(space_id);
3321
3322
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (space == nullptr) {
3323 2 return false;
3324 }
3325
3326 if (x_latched) {
3327 rw_lock_x_unlock(&space->latch);
3328 }
3329
3330 shard->mutex_acquire();
3331 Fil_shard::space_free_low(space);
3332 shard->mutex_release();
3333
3334 ut_a(space == nullptr);
3335
3336 return true;
3337 }
3338
3339 #ifdef UNIV_HOTBACKUP
3340 /** Frees a space object from the tablespace memory cache.
3341 Closes a tablespaces' files but does not delete them.
3342 There must not be any pending i/o's or flushes on the files.
3343 @param[in] space_id Tablespace ID
3344 @return true if success */
3345 bool meb_fil_space_free(space_id_t space_id) {
3346 return fil_space_free(space_id, false);
3347 }
3348 #endif /* UNIV_HOTBACKUP */
3349
3350 /** Create a space memory object and put it to the fil_system hash table.
3351 The tablespace name is independent from the tablespace file-name.
3352 Error messages are issued to the server log.
3353 @param[in] name Tablespace name
3354 @param[in] space_id Tablespace identifier
3355 @param[in] flags Tablespace flags
3356 @param[in] purpose Tablespace purpose
3357 @return pointer to created tablespace, to be filled in with fil_node_create()
3358 @retval nullptr on failure (such as when the same tablespace exists) */
3359 393130 fil_space_t *Fil_shard::space_create(const char *name, space_id_t space_id,
3360 uint32_t flags, fil_type_t purpose,
3361 fil_space_crypt_t *crypt_data,
3362 fil_encryption_t mode) {
3363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
393130 ut_ad(mutex_owned());
3364
3365 /* Look for a matching tablespace. */
3366 393130 fil_space_t *space = get_space_by_name(name);
3367
3368
1/2
✓ Branch 0 taken 393130 times.
✗ Branch 1 not taken.
393130 if (space == nullptr) {
3369 393130 space = get_space_by_id(space_id);
3370 }
3371
3372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
393130 if (space != nullptr) {
3373 std::ostringstream oss;
3374
3375 for (size_t i = 0; i < space->files.size(); ++i) {
3376 oss << "'" << space->files[i].name << "'";
3377
3378 if (i < space->files.size() - 1) {
3379 oss << ", ";
3380 }
3381 }
3382
3383 ut_ad(space->id != space_id);
3384 ib::info(ER_IB_MSG_281)
3385 << "Trying to add tablespace '" << name << "'"
3386 << " with id " << space_id << " to the tablespace"
3387 << " memory cache, but tablespace"
3388 << " '" << space->name << "'"
3389 << " already exists in the cache with space ID " << space->id
3390 << ". It maps to the following file(s): " << oss.str();
3391
3392 return nullptr;
3393 }
3394
3395 space = static_cast<fil_space_t *>(
3396 393130 ut::zalloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, sizeof(*space)));
3397 /* This could be just a placement new constructor call if, only if it compiles
3398 OK on SunPro. */
3399 393130 space->initialize();
3400
3401 393130 space->id = space_id;
3402 393130 space->name = mem_strdup(name);
3403
3404 #ifndef UNIV_HOTBACKUP
3405
2/2
✓ Branch 0 taken 130941 times.
✓ Branch 1 taken 9404 times.
533475 if (fil_system->is_greater_than_max_id(space_id) && !recv_recovery_on &&
3406
4/6
✓ Branch 0 taken 140345 times.
✓ Branch 1 taken 252785 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 130941 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 393130 times.
533475 !dict_sys_t::is_reserved(space_id) &&
3407 !fsp_is_system_temporary(space_id)) {
3408 fil_system->set_maximum_space_id(space);
3409 }
3410 #endif /* !UNIV_HOTBACKUP */
3411
3412 393130 space->purpose = purpose;
3413
3414 393130 space->crypt_data = crypt_data;
3415
3416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 393130 times.
393130 ut_a(flags < std::numeric_limits<uint32_t>::max());
3417 393130 space->flags = (uint32_t)flags;
3418
3419 393130 space->magic_n = FIL_SPACE_MAGIC_N;
3420
3421 393130 space->m_encryption_metadata.m_type = Encryption::NONE;
3422 393130 space->encryption_op_in_progress = Encryption::Progress::NONE;
3423
3424 393130 rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
3425
3426 393130 space->is_corrupt = false;
3427
3428 393130 space->is_space_encrypted = false;
3429
3430 393130 space->exclude_from_rotation = false;
3431
3432 #ifndef UNIV_HOTBACKUP
3433
2/2
✓ Branch 0 taken 106324 times.
✓ Branch 1 taken 286806 times.
393130 if (space->purpose == FIL_TYPE_TEMPORARY) {
3434 106324 ut_d(space->latch.set_temp_fsp());
3435 }
3436 #endif /* !UNIV_HOTBACKUP */
3437
3438 393130 space_add(space, mode);
3439
3440 393130 return space;
3441 }
3442
3443 /** Create a space memory object and put it to the fil_system hash table.
3444 The tablespace name is independent from the tablespace file-name.
3445 Error messages are issued to the server log.
3446 @param[in] name Tablespace name
3447 @param[in] space_id Tablespace ID
3448 @param[in] flags Tablespace flags
3449 @param[in] purpose Tablespace purpose
3450 @return pointer to created tablespace, to be filled in with fil_node_create()
3451 @retval nullptr on failure (such as when the same tablespace exists) */
3452 383713 fil_space_t *fil_space_create(const char *name, space_id_t space_id,
3453 uint32_t flags, fil_type_t purpose,
3454 fil_space_crypt_t *crypt_data,
3455 fil_encryption_t mode) {
3456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383713 times.
383713 ut_ad(fsp_flags_is_valid(flags));
3457
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 383713 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 383713 times.
383713 ut_ad(srv_page_size == UNIV_PAGE_SIZE_ORIG || flags != 0);
3458
3459
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 383711 times.
383713 DBUG_EXECUTE_IF("fil_space_create_failure", return nullptr;);
3460
3461 383711 fil_system->mutex_acquire_all();
3462
3463 383711 auto shard = fil_system->shard_by_id(space_id);
3464
3465 auto space =
3466 383711 shard->space_create(name, space_id, flags, purpose, crypt_data, mode);
3467
3468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383711 times.
383711 if (space == nullptr) {
3469 /* Duplicate error. */
3470 fil_system->mutex_release_all();
3471 return nullptr;
3472 }
3473
3474 /* Cache the system tablespaces, avoid looking them up during IO. */
3475
3476
2/2
✓ Branch 0 taken 9686 times.
✓ Branch 1 taken 374025 times.
383711 if (space->id == TRX_SYS_SPACE) {
3477
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 9686 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9686 times.
9686 ut_a(fil_space_t::s_sys_space == nullptr ||
3478 fil_space_t::s_sys_space == space);
3479
3480 9686 fil_space_t::s_sys_space = space;
3481 }
3482
3483 383711 fil_system->mutex_release_all();
3484
3485 383711 return space;
3486 }
3487
3488 /** Assigns a new space id for a new single-table tablespace. This
3489 works simply by incrementing the global counter. If 4 billion ids
3490 is not enough, we may need to recycle ids.
3491 @param[out] space_id Set this to the new tablespace ID
3492 @return true if assigned, false if not */
3493 196997 bool Fil_system::assign_new_space_id(space_id_t *space_id) {
3494
1/2
✓ Branch 0 taken 196997 times.
✗ Branch 1 not taken.
196997 mutex_acquire_all();
3495
3496 196997 space_id_t id = *space_id;
3497
3498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196997 times.
196997 if (id < m_max_assigned_id) {
3499 id = m_max_assigned_id;
3500 }
3501
3502 196997 ++id;
3503
3504 196997 space_id_t reserved_space_id = dict_sys_t::s_reserved_space_id;
3505
3506
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 196997 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
196997 if (id > (reserved_space_id / 2) && (id % 1000000UL == 0)) {
3507 ib::warn(ER_IB_MSG_282)
3508 << "You are running out of new single-table"
3509 " tablespace id's. Current counter is "
3510 << id << " and it must not exceed " << reserved_space_id
3511 << "! To reset the counter to zero you have to dump"
3512 " all your tables and recreate the whole InnoDB"
3513 " installation.";
3514 }
3515
3516 196997 bool success = !dict_sys_t::is_reserved(id);
3517
3518
1/2
✓ Branch 0 taken 196997 times.
✗ Branch 1 not taken.
196997 if (success) {
3519 196997 *space_id = m_max_assigned_id = id;
3520
3521 } else {
3522 ib::warn(ER_IB_MSG_283) << "You have run out of single-table tablespace"
3523 " id's! Current counter is "
3524 << id
3525 << ". To reset the counter to zero"
3526 " you have to dump all your tables and"
3527 " recreate the whole InnoDB installation.";
3528
3529 *space_id = SPACE_UNKNOWN;
3530 }
3531
3532
1/2
✓ Branch 0 taken 196997 times.
✗ Branch 1 not taken.
196997 mutex_release_all();
3533
3534 196997 return success;
3535 }
3536
3537 /** Assigns a new space id for a new single-table tablespace. This works
3538 simply by incrementing the global counter. If 4 billion id's is not enough,
3539 we may need to recycle id's.
3540 @param[out] space_id Set this to the new tablespace ID
3541 @return true if assigned, false if not */
3542 196997 bool fil_assign_new_space_id(space_id_t *space_id) {
3543 196997 return fil_system->assign_new_space_id(space_id);
3544 }
3545
3546 /** Open the files associated with a tablespace, make sure the size of
3547 the tablespace is read from the header page, and return a pointer to the
3548 fil_space_t that is in the memory cache associated with the given space id.
3549 @param[in] space_id Get the tablespace instance or this ID
3550 @return file_space_t pointer, nullptr if space not found */
3551 425198557 fil_space_t *Fil_shard::space_load(space_id_t space_id) {
3552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1059146043 times.
425198557 ut_ad(mutex_owned());
3553
3554 1059146043 fil_space_t *space = get_space_by_id(space_id);
3555
3556
4/4
✓ Branch 0 taken 1059133654 times.
✓ Branch 1 taken 7766 times.
✓ Branch 2 taken 1059100980 times.
✓ Branch 3 taken 32674 times.
1059141420 if (space == nullptr || space->size != 0) {
3557 1059108746 return space;
3558 }
3559
3560
1/2
✓ Branch 0 taken 32674 times.
✗ Branch 1 not taken.
32674 switch (space->purpose) {
3561 32674 case FIL_TYPE_IMPORT:
3562 case FIL_TYPE_TEMPORARY:
3563 case FIL_TYPE_TABLESPACE:
3564
3565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32673 times.
32674 ut_a(space_id != TRX_SYS_SPACE);
3566
3567 32673 space = get_space_by_id(space_id);
3568
3569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32674 times.
32674 if (space == nullptr) {
3570 return nullptr;
3571 }
3572
3573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32674 times.
32674 ut_a(1 == space->files.size());
3574
3575 {
3576 32674 auto file = &space->files.front();
3577
3578 /* It must be a single-table tablespace and
3579 we have not opened the file yet; the following
3580 calls will open it and update the size fields */
3581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32673 times.
32673 if (!prepare_file_for_io(file)) {
3582 /* The single-table tablespace can't be opened,
3583 because the ibd file is missing. */
3584
3585 return nullptr;
3586 }
3587
3588
1/2
✓ Branch 0 taken 32674 times.
✗ Branch 1 not taken.
32673 complete_io(file, IORequestRead);
3589 }
3590 }
3591
3592 32674 return space;
3593 }
3594
3595 /** Returns the path from the first fil_node_t found with this space ID.
3596 The caller is responsible for freeing the memory allocated here for the
3597 value returned.
3598 @param[in] space_id Tablespace ID
3599 @return own: A copy of fil_node_t::path, nullptr if space ID is zero
3600 or not found. */
3601 464490 char *fil_space_get_first_path(space_id_t space_id) {
3602 464490 auto shard = fil_system->shard_by_id(space_id);
3603
3604 464490 shard->mutex_acquire();
3605
3606 464490 fil_space_t *space = shard->space_load(space_id);
3607
3608 char *path;
3609
3610
2/2
✓ Branch 0 taken 463291 times.
✓ Branch 1 taken 1199 times.
464490 if (space != nullptr) {
3611 463291 path = mem_strdup(space->files.front().name);
3612 } else {
3613 1199 path = nullptr;
3614 }
3615
3616 464490 shard->mutex_release();
3617
3618 464490 return path;
3619 }
3620
3621 /** Returns the size of the space in pages. The tablespace must be cached
3622 in the memory cache.
3623 @param[in] space_id Tablespace ID
3624 @return space size, 0 if space not found */
3625 72669 page_no_t fil_space_get_size(space_id_t space_id) {
3626 72669 auto shard = fil_system->shard_by_id(space_id);
3627
3628 72669 shard->mutex_acquire();
3629
3630 72669 fil_space_t *space = shard->space_load(space_id);
3631
3632
2/2
✓ Branch 0 taken 72668 times.
✓ Branch 1 taken 1 times.
72669 page_no_t size = space ? space->size : 0;
3633
3634 72669 shard->mutex_release();
3635
3636 72669 return size;
3637 }
3638
3639 104778 page_no_t fil_space_get_undo_initial_size(space_id_t space_id) {
3640 104778 auto shard = fil_system->shard_by_id(space_id);
3641
3642 104778 shard->mutex_acquire();
3643
3644 104778 fil_space_t *space = shard->space_load(space_id);
3645
3646
1/2
✓ Branch 0 taken 104778 times.
✗ Branch 1 not taken.
104778 page_no_t size = space ? space->m_undo_initial : 0;
3647
3648 104778 shard->mutex_release();
3649
3650 104778 return size;
3651 }
3652
3653 39219 void fil_space_set_undo_size(space_id_t space_id, bool use_current) {
3654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39219 times.
39219 ut_ad(fsp_is_undo_tablespace(space_id));
3655
3656 39219 auto shard = fil_system->shard_by_id(space_id);
3657
3658 39219 shard->mutex_acquire();
3659
3660 39219 fil_space_t *space = shard->space_load(space_id);
3661
3662
1/2
✓ Branch 0 taken 39219 times.
✗ Branch 1 not taken.
39219 if (space != nullptr) {
3663
2/2
✓ Branch 0 taken 20291 times.
✓ Branch 1 taken 18928 times.
39219 space->m_undo_initial =
3664 18928 (use_current ? space->size : UNDO_INITIAL_SIZE_IN_PAGES);
3665 39219 space->m_undo_extend = UNDO_INITIAL_SIZE_IN_PAGES;
3666 }
3667
3668 39219 shard->mutex_release();
3669 39219 }
3670
3671 /** Returns the flags of the space. The tablespace must be cached
3672 in the memory cache.
3673 @param[in] space_id Tablespace ID for which to get the flags
3674 @return flags, ULINT_UNDEFINED if space not found */
3675 1058175077 uint32_t fil_space_get_flags(space_id_t space_id) {
3676 1058175077 auto shard = fil_system->shard_by_id(space_id);
3677
3678 1058178168 shard->mutex_acquire();
3679
3680 1058191974 fil_space_t *space = shard->space_load(space_id);
3681
3682 uint32_t flags;
3683
3684
2/2
✓ Branch 0 taken 1058180007 times.
✓ Branch 1 taken 6816 times.
1058186823 flags = (space != nullptr) ? space->flags : UINT32_UNDEFINED;
3685
3686 1058186823 shard->mutex_release();
3687
3688 1058198815 return flags;
3689 }
3690
3691 /** Open each file of a tablespace if not already open.
3692 @param[in] space_id tablespace identifier
3693 @retval true if all file nodes were opened
3694 @retval false on failure */
3695 35013 bool Fil_shard::space_open(space_id_t space_id) {
3696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35013 times.
35013 ut_ad(mutex_owned());
3697
3698 35013 fil_space_t *space = get_space_by_id(space_id);
3699
3700
2/2
✓ Branch 0 taken 35013 times.
✓ Branch 1 taken 35013 times.
70026 for (auto &file : space->files) {
3701
5/8
✓ Branch 0 taken 29838 times.
✓ Branch 1 taken 5175 times.
✓ Branch 2 taken 29838 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29838 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 35013 times.
35013 if (!file.is_open && !open_file(&file)) {
3702 return false;
3703 }
3704 }
3705
3706 35013 return true;
3707 }
3708
3709 /** Open each file of a tablespace if not already open.
3710 @param[in] space_id Tablespace ID
3711 @retval true if all file nodes were opened
3712 @retval false on failure */
3713 35013 bool fil_space_open(space_id_t space_id) {
3714 35013 auto shard = fil_system->shard_by_id(space_id);
3715
3716 35013 shard->mutex_acquire();
3717
3718 35013 bool success = shard->space_open(space_id);
3719
3720 35013 shard->mutex_release();
3721
3722 35013 return success;
3723 }
3724
3725 /** Close each file of a tablespace if open.
3726 @param[in] space_id Tablespace ID */
3727 178363 void fil_space_close(space_id_t space_id) {
3728
2/2
✓ Branch 0 taken 8267 times.
✓ Branch 1 taken 170096 times.
178363 if (fil_system == nullptr) {
3729 8267 return;
3730 }
3731
3732 170096 auto shard = fil_system->shard_by_id(space_id);
3733
3734 170096 shard->close_file(space_id);
3735 }
3736
3737 /** Returns the page size of the space and whether it is compressed or not.
3738 The tablespace must be cached in the memory cache.
3739 @param[in] space_id Tablespace ID
3740 @param[out] found true if tablespace was found
3741 @return page size */
3742 1057783328 const page_size_t fil_space_get_page_size(space_id_t space_id, bool *found) {
3743 1057783328 const uint32_t flags = fil_space_get_flags(space_id);
3744
3745
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1057813020 times.
1057813070 if (flags == UINT32_UNDEFINED) {
3746 50 *found = false;
3747 50 return univ_page_size;
3748 }
3749
3750 1057813020 *found = true;
3751
3752 1057813020 return page_size_t(flags);
3753 }
3754
3755 /** Initializes the tablespace memory cache.
3756 @param[in] max_n_open Maximum number of open files */
3757 9805 void fil_init(ulint max_n_open) {
3758 static_assert((1 << UNIV_PAGE_SIZE_SHIFT_MAX) == UNIV_PAGE_SIZE_MAX,
3759 "(1 << UNIV_PAGE_SIZE_SHIFT_MAX) != UNIV_PAGE_SIZE_MAX");
3760
3761 static_assert((1 << UNIV_PAGE_SIZE_SHIFT_MIN) == UNIV_PAGE_SIZE_MIN,
3762 "(1 << UNIV_PAGE_SIZE_SHIFT_MIN) != UNIV_PAGE_SIZE_MIN");
3763
3764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9805 times.
9805 ut_a(fil_system == nullptr);
3765
3766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9805 times.
9805 ut_a(max_n_open > 0);
3767
3768 9805 fil_system = ut::new_withkey<Fil_system>(UT_NEW_THIS_FILE_PSI_KEY, MAX_SHARDS,
3769 max_n_open);
3770
3771 9805 fil_space_crypt_init();
3772 9805 }
3773
3774 16 bool fil_open_files_limit_update(size_t &new_max_open_files) {
3775 16 return fil_system->set_open_files_limit(new_max_open_files);
3776 }
3777
3778 16 bool Fil_system::set_open_files_limit(size_t &new_max_open_files) {
3779 16 const auto start_time = std::chrono::steady_clock::now();
3780 {
3781 const auto current_minimum_limit_for_open_files =
3782
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 get_minimum_limit_for_open_files(m_n_files_not_belonging_in_lru);
3783
3784
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
16 if (new_max_open_files < current_minimum_limit_for_open_files) {
3785 /* Use the same value that was used for the check, to not mislead user
3786 with other value than was used in calculations. */
3787 3 new_max_open_files = current_minimum_limit_for_open_files;
3788 3 return false;
3789 }
3790 }
3791 /* We impose our new limit to not allow new file openings to cross new limits
3792 (including non-LRU limit). */
3793
3/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12 times.
13 if (!m_open_files_limit.set_desired_limit(new_max_open_files)) {
3794 1 new_max_open_files = 0;
3795 1 return false;
3796 }
3797
3798 /* We read the m_n_files_not_belonging_in_lru again after the
3799 m_open_files_limit write is issued. */
3800 const auto current_minimum_limit_for_open_files =
3801
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 get_minimum_limit_for_open_files(m_n_files_not_belonging_in_lru);
3802
3803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (new_max_open_files < current_minimum_limit_for_open_files) {
3804 /* The limit was already exceeded while we were setting the
3805 m_open_files_limit.get_limit(). We rollback from the limit change. There is
3806 a counterpart check in the `Fil_shard::open_file` to rollback the limit
3807 reservation if this case is encountered there. */
3808 m_open_files_limit.revert_desired_limit();
3809
3810 /* Use the same value that was used for the check, to not mislead user with
3811 other value than was used in calculations. */
3812 new_max_open_files = current_minimum_limit_for_open_files;
3813 return false;
3814 }
3815
3816 12 const auto set_new_limit_timeout = std::chrono::seconds(5);
3817
3818 for (;;) {
3819 37 auto current_n_files_open = fil_n_files_open.load();
3820
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 25 times.
37 if ((size_t)new_max_open_files >= current_n_files_open) {
3821 12 break;
3822 }
3823
3/6
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25 times.
25 if (std::chrono::steady_clock::now() - start_time > set_new_limit_timeout) {
3824 /* Timeout, let's rollback the limit change and recommend a new limit. */
3825 m_open_files_limit.revert_desired_limit();
3826
3827 /* Use the same value that was used for the check, to not mislead user
3828 with other value than was used in calculations. */
3829 new_max_open_files = current_n_files_open;
3830 return false;
3831 }
3832
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 fil_system->flush_file_spaces();
3833
3834
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
25 if (fil_system->close_file_in_all_LRU()) {
3835 /* We closed some file, loop again to re-evaluate situation. */
3836 25 continue;
3837 }
3838 wait_while_ios_in_progress();
3839 25 }
3840
3841 #ifndef UNIV_HOTBACKUP
3842 /* Set the new limit in system variable. */
3843
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 innobase_set_open_files_limit(new_max_open_files);
3844
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 m_open_files_limit.commit_desired_limit();
3845 #endif
3846
3847 12 return true;
3848 }
3849
3850 /** Open all the system files.
3851 @param[in] max_n_open Maximum number of open files allowed
3852 @param[in,out] n_open Current number of open files */
3853 660688 void Fil_shard::open_system_tablespaces(size_t max_n_open, size_t *n_open) {
3854 660688 mutex_acquire();
3855
3856
2/2
✓ Branch 0 taken 9997 times.
✓ Branch 1 taken 660688 times.
670685 for (auto elem : m_spaces) {
3857 9997 auto space = elem.second;
3858
3859
3/4
✓ Branch 0 taken 9997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299 times.
✓ Branch 3 taken 9698 times.
9997 if (Fil_system::space_belongs_in_LRU(space)) {
3860 299 continue;
3861 }
3862
3863
2/2
✓ Branch 0 taken 9723 times.
✓ Branch 1 taken 9698 times.
19421 for (auto &file : space->files) {
3864
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 9699 times.
9723 if (!file.is_open) {
3865
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 if (!open_file(&file)) {
3866 /* This func is called during server's startup. If some file of log
3867 or system tablespace is missing, the server can't start
3868 successfully. So we should assert for it. */
3869 ut_error;
3870 }
3871
3872 24 ++*n_open;
3873 }
3874
3875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9723 times.
9723 if (max_n_open < 10 + *n_open) {
3876 ib::warn(ER_IB_MSG_284, *n_open, max_n_open);
3877 }
3878 }
3879 }
3880
3881 660688 mutex_release();
3882 660688 }
3883
3884 /** Opens all system tablespace data files in all shards. */
3885 9716 void Fil_system::open_all_system_tablespaces() {
3886 9716 size_t n_open = 0;
3887
3888
2/2
✓ Branch 0 taken 660688 times.
✓ Branch 1 taken 9716 times.
670404 for (auto shard : m_shards) {
3889
1/2
✓ Branch 0 taken 660688 times.
✗ Branch 1 not taken.
660688 shard->open_system_tablespaces(get_open_files_limit(), &n_open);
3890 }
3891 9716 }
3892
3893 /** Opens all system tablespace data files. They stay open until the
3894 database server shutdown. This should be called at a server startup
3895 after the space objects for the log and the system tablespace have
3896 been created. The purpose of this operation is to make sure we never
3897 run out of file descriptors if we need to read from the insert buffer
3898 or to write to the log. */
3899 9716 void fil_open_system_tablespace_files() {
3900 9716 fil_system->open_all_system_tablespaces();
3901 9716 }
3902
3903 #ifndef UNIV_HOTBACKUP
3904 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
3905 2873 static void fil_validate_space_reference_count(
3906 fil_space_t *space, Space_References &buffer_pool_references) {
3907
1/2
✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
2873 const auto space_reference_count = space->get_reference_count();
3908
3909
2/4
✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2873 times.
2873 if (space_reference_count != buffer_pool_references[space]) {
3910 ib::error() << "Space id=" << space->id << " reference count is "
3911 << space_reference_count
3912 << ", while references count found in buffer pool is "
3913 << buffer_pool_references[space] << ". fast_shutdown is "
3914 << srv_fast_shutdown;
3915 }
3916 2873 }
3917
3918 14008 void Fil_shard::validate_space_reference_count(
3919 Space_References &buffer_pool_references) {
3920
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14008 times.
14008 ut_ad(!mutex_owned());
3921
3922 14008 mutex_acquire();
3923
3924
2/2
✓ Branch 0 taken 2827 times.
✓ Branch 1 taken 14008 times.
16835 for (auto &e : m_spaces) {
3925
1/2
✓ Branch 0 taken 2827 times.
✗ Branch 1 not taken.
2827 fil_validate_space_reference_count(e.second, buffer_pool_references);
3926 }
3927
3928
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 14008 times.
14054 for (auto &e : m_deleted_spaces) {
3929
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 fil_validate_space_reference_count(e.second, buffer_pool_references);
3930 }
3931
3932 14008 mutex_release();
3933 14008 }
3934 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
3935 #endif /* !UNIV_HOTBACKUP */
3936
3937 569772 void Fil_shard::close_all_files() {
3938
2/4
✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 569772 times.
569772 ut_ad(mutex_owned());
3939
3940 /* Iterates over a specified container of pair */
3941 2279092 auto iterate_all_spaces_files = [this](auto &spaces, auto preprocess_space,
3942 140956 auto postprocess_space) {
3943
2/2
✓ Branch 0 taken 178580 times.
✓ Branch 1 taken 1139544 times.
2636248 for (auto &e : spaces) {
3944 357160 auto &space = e.second;
3945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 178580 times.
357160 if (space == nullptr) {
3946 continue;
3947 }
3948
3949
1/2
✓ Branch 0 taken 178580 times.
✗ Branch 1 not taken.
357160 preprocess_space(space);
3950
3951
2/2
✓ Branch 0 taken 178608 times.
✓ Branch 1 taken 178578 times.
714372 for (auto &file : space->files) {
3952
7/8
✓ Branch 0 taken 70476 times.
✓ Branch 1 taken 108132 times.
✓ Branch 2 taken 70476 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 70474 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 178606 times.
357216 if (file.is_open && !file.can_be_closed()) {
3953
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 mutex_release();
3954
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 std::this_thread::sleep_for(std::chrono::milliseconds{1});
3955
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 mutex_acquire();
3956 /* Files or spaces could have changed when we did not hold the
3957 mutex, restart the loop. */
3958 4 return false;
3959 }
3960
2/2
✓ Branch 0 taken 70474 times.
✓ Branch 1 taken 108132 times.
357212 if (file.is_open) {
3961
1/2
✓ Branch 0 taken 70474 times.
✗ Branch 1 not taken.
140948 close_file(&file);
3962 }
3963 }
3964
3965
1/2
✓ Branch 0 taken 174465 times.
✗ Branch 1 not taken.
357156 postprocess_space(space);
3966
3967
1/2
✓ Branch 0 taken 178578 times.
✗ Branch 1 not taken.
357156 space_free_low(space);
3968
3969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 178578 times.
357156 ut_a(space == nullptr);
3970 }
3971 2279088 return true;
3972 569772 };
3973
3974 for (;;) {
3975
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 569772 times.
569774 if (!iterate_all_spaces_files(
3976
1/2
✓ Branch 0 taken 569774 times.
✗ Branch 1 not taken.
569774 m_spaces,
3977 174467 [](auto space) {
3978
6/8
✓ Branch 0 taken 166198 times.
✓ Branch 1 taken 8269 times.
✓ Branch 2 taken 74791 times.
✓ Branch 3 taken 91407 times.
✓ Branch 4 taken 74791 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 174467 times.
174467 ut_a(space->id == TRX_SYS_SPACE ||
3979 space->purpose == FIL_TYPE_TEMPORARY ||
3980 space->files.size() == 1);
3981 174467 },
3982 174465 [this](auto space) { space_detach(space); })) {
3983 2 continue;
3984 }
3985
3986 569772 m_spaces.clear();
3987
3988 #ifndef UNIV_HOTBACKUP
3989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 569772 times.
569772 if (!iterate_all_spaces_files(
3990
1/2
✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
569772 m_deleted_spaces,
3991 4113 [](auto space) {
3992
3/6
✓ Branch 0 taken 4113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4113 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4113 times.
4113 ut_a(space->id != TRX_SYS_SPACE &&
3993 space->id != dict_sys_t::s_dict_space_id);
3994
3995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4113 times.
4113 ut_a(space->files.size() <= 1);
3996 4113 },
3997 4113 [](auto) {})) {
3998 continue;
3999 }
4000
4001 569772 m_deleted_spaces.clear();
4002 #endif /* !UNIV_HOTBACKUP */
4003 569772 break;
4004 2 }
4005 569772 }
4006
4007 /** Close all open files. */
4008 8379 void Fil_system::close_all_files() {
4009 #ifndef UNIV_HOTBACKUP
4010 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
4011 8379 bool should_validate_space_reference_count = srv_fast_shutdown == 0;
4012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8379 times.
8379 DBUG_EXECUTE_IF("buf_disable_space_reference_count_check",
4013 should_validate_space_reference_count = false;);
4014
4015
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 8173 times.
8379 if (should_validate_space_reference_count) {
4016
1/2
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
206 auto buffer_pool_references = buf_LRU_count_space_references();
4017
2/2
✓ Branch 0 taken 14008 times.
✓ Branch 1 taken 206 times.
14214 for (auto shard : m_shards) {
4018
1/2
✓ Branch 0 taken 14008 times.
✗ Branch 1 not taken.
14008 shard->validate_space_reference_count(buffer_pool_references);
4019 }
4020 206 }
4021 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
4022 #endif /* !UNIV_HOTBACKUP */
4023
4024
2/2
✓ Branch 0 taken 569772 times.
✓ Branch 1 taken 8379 times.
578151 for (auto shard : m_shards) {
4025
1/2
✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
569772 shard->mutex_acquire();
4026
4027
1/2
✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
569772 shard->close_all_files();
4028
4029
1/2
✓ Branch 0 taken 569772 times.
✗ Branch 1 not taken.
569772 shard->mutex_release();
4030 }
4031
4032 #ifndef UNIV_HOTBACKUP
4033 /* Revert to old names if downgrading after upgrade failure. */
4034
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 8349 times.
8379 if (srv_downgrade_partition_files) {
4035 30 rename_partition_files(true);
4036 }
4037
4038 8379 clear_old_files();
4039 #endif /* !UNIV_HOTBACKUP */
4040 8379 }
4041
4042 /** Closes all open files. There must not be any pending i/o's or not flushed
4043 modifications in the files. */
4044 8379 void fil_close_all_files() {
4045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8379 times.
8379 if (!fil_system) return;
4046
4047 8379 fil_system->close_all_files();
4048 }
4049
4050 /** Iterate through all persistent tablespace files (FIL_TYPE_TABLESPACE)
4051 returning the nodes via callback function cbk.
4052 @param[in] f Callback
4053 @return any error returned by the callback function. */
4054 52360 dberr_t Fil_shard::iterate(Fil_iterator::Function &f) {
4055 52360 mutex_acquire();
4056
4057
2/2
✓ Branch 0 taken 19576 times.
✓ Branch 1 taken 52360 times.
71936 for (auto &elem : m_spaces) {
4058 19576 auto space = elem.second;
4059
4060
2/2
✓ Branch 0 taken 8470 times.
✓ Branch 1 taken 11106 times.
19576 if (space->purpose != FIL_TYPE_TABLESPACE) {
4061 8470 continue;
4062 }
4063
4064
2/2
✓ Branch 0 taken 11118 times.
✓ Branch 1 taken 11106 times.
22224 for (auto &file : space->files) {
4065 /* Note: The callback can release the mutex. */
4066
4067
1/2
✓ Branch 0 taken 11118 times.
✗ Branch 1 not taken.
11118 dberr_t err = f(&file);
4068
4069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11118 times.
11118 if (err != DB_SUCCESS) {
4070 mutex_release();
4071
4072 return err;
4073 }
4074 }
4075 }
4076
4077 52360 mutex_release();
4078
4079 52360 return DB_SUCCESS;
4080 }
4081
4082 770 dberr_t Fil_system::iterate(Fil_iterator::Function &f) {
4083
2/2
✓ Branch 0 taken 52360 times.
✓ Branch 1 taken 770 times.
53130 for (auto shard : m_shards) {
4084
1/2
✓ Branch 0 taken 52360 times.
✗ Branch 1 not taken.
52360 dberr_t err = shard->iterate(f);
4085
4086
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52360 times.
52360 if (err != DB_SUCCESS) {
4087 return err;
4088 }
4089 }
4090
4091 770 return DB_SUCCESS;
4092 }
4093
4094 770 dberr_t Fil_iterator::iterate(Function &&f) { return fil_system->iterate(f); }
4095
4096 /** Sets the max tablespace id counter if the given number is bigger than the
4097 previous value.
4098 @param[in] max_id Maximum known tablespace ID */
4099 28614 void fil_set_max_space_id_if_bigger(space_id_t max_id) {
4100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28614 times.
28614 if (dict_sys_t::is_reserved(max_id)) {
4101 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_285, ulong{max_id});
4102 }
4103
4104 28614 fil_system->update_maximum_space_id(max_id);
4105 28614 }
4106
4107 /** Write the flushed LSN to the page header of the first page in the
4108 system tablespace.
4109 @param[in] lsn Flushed LSN
4110 @return DB_SUCCESS or error number */
4111 8663 dberr_t fil_write_flushed_lsn(lsn_t lsn) {
4112 dberr_t err;
4113
4114 auto buf =
4115 8663 static_cast<byte *>(ut::aligned_alloc(UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
4116
4117 8663 const page_id_t page_id(TRX_SYS_SPACE, 0);
4118
4119
2/4
✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8663 times.
✗ Branch 3 not taken.
8663 err = fil_read(page_id, univ_page_size, 0, univ_page_size.physical(), buf);
4120
4121
1/2
✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
8663 if (err == DB_SUCCESS) {
4122
1/2
✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
8663 mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn);
4123
4124
2/4
✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8663 times.
✗ Branch 3 not taken.
8663 err = fil_write(page_id, univ_page_size, 0, univ_page_size.physical(), buf);
4125
4126
1/2
✓ Branch 0 taken 8663 times.
✗ Branch 1 not taken.
8663 fil_system->flush_file_spaces();
4127 }
4128
4129 8663 ut::aligned_free(buf);
4130
4131 8663 return err;
4132 }
4133
4134 /** Acquire a tablespace when it could be dropped concurrently.
4135 Used by background threads that do not necessarily hold proper locks
4136 for concurrency control.
4137 @param[in] space_id Tablespace ID
4138 @param[in] silent Whether to silently ignore missing tablespaces
4139 @return the tablespace, or nullptr if missing or being deleted */
4140 30004423 fil_space_t *Fil_system::space_acquire(space_id_t space_id, bool silent) {
4141 30004423 auto shard = fil_system->shard_by_id(space_id);
4142
4143 30006077 shard->mutex_acquire();
4144
4145 30007420 fil_space_t *space = shard->get_space_by_id(space_id);
4146
4147
2/2
✓ Branch 0 taken 16413 times.
✓ Branch 1 taken 29991009 times.
30007422 if (space == nullptr) {
4148
6/6
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 16346 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 16406 times.
16413 if (!silent && m_ACCESSING_NONEXISTINC_SPACE_throttler.apply()) {
4149
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ib::warn(ER_IB_WARN_ACCESSING_NONEXISTINC_SPACE, ulong{space_id});
4150 }
4151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29991015 times.
29991009 } else if (!shard->space_acquire(space)) {
4152 space = nullptr;
4153 }
4154
4155 30007428 shard->mutex_release();
4156
4157 30007512 return space;
4158 }
4159
4160 29990887 inline bool Fil_shard::space_acquire(fil_space_t *space) {
4161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29990991 times.
29990887 ut_ad(mutex_owned());
4162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29991026 times.
29990991 ut_ad(space != nullptr);
4163
4164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29991026 times.
29991026 if (space->stop_new_ops) {
4165 return false;
4166 }
4167
4168 29991026 ++space->n_pending_ops;
4169
4170 29991026 return true;
4171 }
4172
4173 /** Acquire a tablespace when it could be dropped concurrently.
4174 Used by background threads that do not necessarily hold proper locks
4175 for concurrency control.
4176 @param[in] space_id Tablespace ID
4177 @return the tablespace, or nullptr if missing or being deleted */
4178 1129809 fil_space_t *fil_space_acquire(space_id_t space_id) {
4179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1129809 times.
1129809 if (!fil_system) return nullptr;
4180 1129809 return fil_system->space_acquire(space_id, false);
4181 }
4182
4183 /** Acquire a tablespace that may not exist.
4184 Used by background threads that do not necessarily hold proper locks
4185 for concurrency control.
4186 @param[in] space_id Tablespace ID
4187 @return the tablespace, or nullptr if missing or being deleted */
4188 28874766 fil_space_t *fil_space_acquire_silent(space_id_t space_id) {
4189 28874766 return fil_system->space_acquire(space_id, true);
4190 }
4191
4192 /** Release a tablespace acquired with fil_space_acquire().
4193 @param[in,out] space Tablespace to release */
4194 29990817 void fil_space_release(fil_space_t *space) {
4195 29990817 auto shard = fil_system->shard_by_id(space->id);
4196
4197 29991071 shard->mutex_acquire();
4198 29991052 shard->space_release(space);
4199 29990975 shard->mutex_release();
4200 29991096 }
4201
4202 /** Release a tablespace acquired with Fil_shard::space_acquire().
4203 @param[in,out] space tablespace to release */
4204 29990930 void Fil_shard::space_release(fil_space_t *space) {
4205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29990974 times.
29990930 ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
4206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29990964 times.
29990974 ut_ad(space->n_pending_ops > 0);
4207
4208 29990964 --space->n_pending_ops;
4209 29990964 }
4210
4211 /** Acquire a tablespace for reading or writing a block,
4212 when it could be dropped concurrently.
4213 @param[in] id tablespace ID
4214 @return the tablespace
4215 @retval NULL if missing */
4216 45206213 fil_space_t *fil_space_acquire_for_io(space_id_t space_id) {
4217 45206213 auto shard = fil_system->shard_by_id(space_id);
4218
4219 45206858 shard->mutex_acquire();
4220
4221 45207604 fil_space_t *space = shard->get_space_by_id(space_id);
4222
4223
2/2
✓ Branch 0 taken 45207569 times.
✓ Branch 1 taken 11 times.
45207580 if (space) {
4224 45207569 space->n_pending_ios++;
4225 }
4226
4227 45207580 shard->mutex_release();
4228
4229 45207664 return (space);
4230 }
4231
4232 /** Acquire a tablespace for reading or writing a block,
4233 when it could be dropped concurrently.
4234 @param[in] id tablespace ID
4235 @return the tablespace
4236 @retval NULL if missing */
4237 273556 fil_space_t *fil_space_acquire_for_io_with_load(space_id_t space_id) {
4238 273556 auto shard = fil_system->shard_by_id(space_id);
4239
4240 273556 shard->mutex_acquire();
4241
4242 273556 fil_space_t *space = shard->space_load(space_id);
4243
4244
1/2
✓ Branch 0 taken 273556 times.
✗ Branch 1 not taken.
273556 if (space) {
4245 273556 space->n_pending_ios++;
4246 }
4247
4248 273556 shard->mutex_release();
4249
4250 273556 return (space);
4251 }
4252
4253 /** Release a tablespace acquired with fil_space_acquire_for_io().
4254 @param[in,out] space tablespace to release */
4255 45480184 void fil_space_release_for_io(fil_space_t *space) {
4256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45480526 times.
45480184 ut_ad(space);
4257 45480526 auto shard = fil_system->shard_by_id(space->id);
4258
4259 45480606 shard->mutex_acquire();
4260
4261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45481155 times.
45481141 ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
4262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45481153 times.
45481155 ut_ad(space->n_pending_ios > 0);
4263
4264 45481153 --space->n_pending_ios;
4265
4266 45481153 shard->mutex_release();
4267 45481186 }
4268
4269 3544 fil_space_t *fil_space_get_next_in_shard(fil_space_t *space, Fil_shard *shard) {
4270
2/2
✓ Branch 0 taken 3130 times.
✓ Branch 1 taken 414 times.
3544 space = (space == nullptr) ? UT_LIST_GET_FIRST(shard->m_space_list)
4271 : UT_LIST_GET_NEXT(space_list, space);
4272 /* Skip spaces that are being created by
4273 fil_ibd_create(), or dropped, or !tablespace. */
4274
6/8
✓ Branch 0 taken 922 times.
✓ Branch 1 taken 3128 times.
✓ Branch 2 taken 922 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 922 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 506 times.
✓ Branch 7 taken 3544 times.
4972 while (space != nullptr && (space->files.empty() || space->is_stopping() ||
4275
2/2
✓ Branch 0 taken 506 times.
✓ Branch 1 taken 416 times.
922 space->purpose != FIL_TYPE_TABLESPACE)) {
4276 506 space = UT_LIST_GET_NEXT(space_list, space);
4277 }
4278 3544 return space;
4279 }
4280
4281 /**
4282 Remove space from key rotation list if there are no more
4283 pending operations.
4284 @param[in] space Tablespace */
4285 static void fil_space_remove_from_keyrotation(Fil_shard *shard,
4286 fil_space_t *space) {
4287 ut_ad(shard->mutex_owned());
4288 ut_ad(space);
4289
4290 if (space->n_pending_ops == 0 && space->is_in_rotation_list) {
4291 space->is_in_rotation_list = false;
4292 ut_a(UT_LIST_GET_LEN(shard->m_rotation_list) > 0);
4293 UT_LIST_REMOVE(shard->m_rotation_list, space);
4294 }
4295 }
4296
4297 fil_space_t *fil_space_get_next_in_shards_rotation_list(fil_space_t *space,
4298 Fil_shard *shard) {
4299 if (space == nullptr) {
4300 space = UT_LIST_GET_FIRST(shard->m_rotation_list);
4301 } else {
4302 fil_space_t *prev_space = space;
4303 space = UT_LIST_GET_NEXT(rotation_list, prev_space);
4304 fil_space_remove_from_keyrotation(shard, prev_space);
4305 }
4306 /* Skip spaces that are being created by
4307 fil_ibd_create(), or dropped, or !tablespace. */
4308 while (space != nullptr && (space->files.empty() || space->is_stopping() ||
4309 space->purpose != FIL_TYPE_TABLESPACE)) {
4310 fil_space_t *prev_space = space;
4311 space = UT_LIST_GET_NEXT(rotation_list, prev_space);
4312 fil_space_remove_from_keyrotation(shard, prev_space);
4313 }
4314 return space;
4315 }
4316
4317 /** Return the next fil_space_t.
4318 Once started, the caller must keep calling this until it returns NULL.
4319 fil_space_acquire() and fil_space_t::release() are invoked here which
4320 blocks a concurrent operation from dropping the tablespace.
4321 @param[in] prev_space Pointer to the previous fil_space_t.
4322 If NULL, use the first fil_space_t on fil_system.space_list.
4323 @return pointer to the next fil_space_t.
4324 @retval NULL if this was the last*/
4325 462 fil_space_t *fil_space_next(
4326 fil_space_t *prev_space) // TODO: It should be a part of Fil_system
4327 {
4328 462 fil_space_t *space = prev_space;
4329
4330
1/2
✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
462 mutex_enter(&fil_crypt_list_mutex);
4331
4332 462 Fil_shard *shard = nullptr;
4333 462 uint shard_index = 0;
4334
4335
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 414 times.
462 if (prev_space == nullptr) {
4336
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 shard = fil_system->shard_by_index(shard_index);
4337
4338
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 shard->mutex_acquire();
4339
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 space = fil_space_get_next_in_shard(prev_space, shard);
4340 }
4341
4342
2/2
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 48 times.
462 if (prev_space != nullptr) {
4343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 414 times.
414 ut_ad(space->n_pending_ops >
4344 0); // we are sure that space exists as space
4345 // with n_pending_ops > 0 cannot be removed
4346
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 shard = fil_system->shard_by_id(space->id, &shard_index);
4347
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 shard->mutex_acquire();
4348
4349 /* Move on to the next fil_space_t */
4350 414 space->n_pending_ops--;
4351
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 space = fil_space_get_next_in_shard(space, shard);
4352 }
4353
4354
6/6
✓ Branch 0 taken 3128 times.
✓ Branch 1 taken 416 times.
✓ Branch 2 taken 3082 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 3082 times.
✓ Branch 5 taken 462 times.
6672 while (space == nullptr &&
4355 3128 (++shard_index < fil_system->get_number_of_shards())) {
4356
1/2
✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
3082 shard->mutex_release();
4357
1/2
✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
3082 shard = fil_system->shard_by_index(shard_index);
4358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3082 times.
3082 ut_ad(shard != nullptr);
4359
1/2
✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
3082 shard->mutex_acquire();
4360
1/2
✓ Branch 0 taken 3082 times.
✗ Branch 1 not taken.
3082 space = fil_space_get_next_in_shard(space, shard);
4361 }
4362
4363
2/2
✓ Branch 0 taken 416 times.
✓ Branch 1 taken 46 times.
462 if (space != nullptr) {
4364 416 space->n_pending_ops++;
4365 }
4366
4367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 462 times.
462 ut_ad(shard != nullptr);
4368
1/2
✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
462 shard->mutex_release();
4369
1/2
✓ Branch 0 taken 462 times.
✗ Branch 1 not taken.
462 mutex_exit(&fil_crypt_list_mutex);
4370
4371 462 return (space);
4372 }
4373
4374 /** Return the next fil_space_t from key rotation list.
4375 Once started, the caller must keep calling this until it returns NULL.
4376 fil_space_acquire() and fil_space_release() are invoked here which
4377 blocks a concurrent operation from dropping the tablespace.
4378 @param[in] prev_space Pointer to the previous fil_space_t.
4379 If NULL, use the first fil_space_t on fil_system->space_list.
4380 @return pointer to the next fil_space_t.
4381 @retval NULL if this was the last*/
4382 fil_space_t *fil_space_keyrotate_next(
4383 fil_space_t *prev_space) { // TODO: To powinno być częścią Fil_system
4384
4385 fil_space_t *space = prev_space;
4386 mutex_enter(&fil_crypt_list_mutex);
4387
4388 Fil_shard *shard = nullptr;
4389 uint shard_index = 0;
4390
4391 if (prev_space == nullptr) {
4392 shard = fil_system->shard_by_index(shard_index);
4393
4394 shard->mutex_acquire();
4395 space = fil_space_get_next_in_shards_rotation_list(prev_space, shard);
4396 }
4397
4398 if (prev_space != NULL) {
4399 ut_ad(space->n_pending_ops >
4400 0); // we are sure that space exists as space
4401 // with n_pending_ops > 0 cannot be removed
4402 uint shard_index = 0;
4403 shard = fil_system->shard_by_id(space->id, &shard_index);
4404 shard->mutex_acquire();
4405 /* Move on to the next fil_space_t */
4406 space->n_pending_ops--;
4407 space = fil_space_get_next_in_shards_rotation_list(prev_space, shard);
4408 }
4409
4410 while (space == nullptr &&
4411 (++shard_index < fil_system->get_number_of_shards())) {
4412 shard->mutex_release();
4413 shard = fil_system->shard_by_index(shard_index);
4414 ut_ad(shard != nullptr);
4415 shard->mutex_acquire();
4416 space = fil_space_get_next_in_shards_rotation_list(space, shard);
4417 }
4418
4419 if (space != nullptr) {
4420 space->n_pending_ops++;
4421 }
4422
4423 ut_ad(shard != nullptr);
4424 shard->mutex_release();
4425 mutex_exit(&fil_crypt_list_mutex);
4426
4427 return space;
4428 }
4429
4430 /** Check for pending operations.
4431 @param[in] space tablespace
4432 @param[in] count number of attempts so far
4433 @return 0 if no pending operations else count + 1. */
4434 267044 ulint Fil_shard::space_check_pending_operations(fil_space_t *space,
4435 ulint count) const {
4436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
267044 ut_ad(mutex_owned());
4437
4438
3/4
✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 163 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 266881 times.
267044 if (space != nullptr && space->n_pending_ops > 0) {
4439 if (count > 5000) {
4440 ib::warn(ER_IB_MSG_287, space->name, ulong{space->n_pending_ops});
4441 }
4442
4443 return count + 1;
4444 }
4445
4446 267044 return 0;
4447 }
4448
4449 /** Check for pending IO.
4450 @param[in] space Tablespace to check
4451 @param[in] file File in space list
4452 @param[in] count number of attempts so far
4453 @return 0 if no pending else count + 1. */
4454 267398 ulint Fil_shard::check_pending_io(const fil_space_t *space,
4455 const fil_node_t &file, ulint count) const {
4456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267398 times.
267398 ut_ad(mutex_owned());
4457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267398 times.
267398 ut_a(space->n_pending_ops == 0);
4458
4459
5/8
✓ Branch 0 taken 267398 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188010 times.
✓ Branch 3 taken 79388 times.
✓ Branch 4 taken 188010 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 267398 times.
267398 ut_a(space->id == TRX_SYS_SPACE || space->purpose == FIL_TYPE_TEMPORARY ||
4460 space->files.size() == 1);
4461
4462
4/4
✓ Branch 0 taken 266972 times.
✓ Branch 1 taken 426 times.
✓ Branch 2 taken 91 times.
✓ Branch 3 taken 266881 times.
267398 if (space->n_pending_flushes > 0 || file.n_pending_ios > 0) {
4463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 517 times.
517 if (count > 1000) {
4464 ib::warn(ER_IB_MSG_288, space->name, ulong{space->n_pending_flushes},
4465 size_t{file.n_pending_ios});
4466 }
4467
4468 517 return count + 1;
4469 }
4470
4471 266881 return 0;
4472 }
4473
4474 267044 dberr_t Fil_shard::wait_for_pending_operations(space_id_t space_id,
4475 fil_space_t *&space,
4476 char **path) const {
4477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
267044 ut_ad(!fsp_is_system_tablespace(space_id));
4478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
267044 ut_ad(!fsp_is_global_temporary(space_id));
4479
4480 267044 space = nullptr;
4481
4482 267044 mutex_acquire();
4483
4484 267044 fil_space_t *sp = get_space_by_id(space_id);
4485
4486
2/2
✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 163 times.
267044 if (sp != nullptr) {
4487 266881 sp->stop_new_ops = true;
4488
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 266871 times.
266881 if (sp->crypt_data) {
4489 10 sp->n_pending_ops++;
4490 10 mutex_release();
4491 10 fil_space_crypt_close_tablespace(sp);
4492 10 mutex_acquire();
4493
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 ut_ad(sp->n_pending_ops > 0);
4494 10 sp->n_pending_ops--;
4495 }
4496 }
4497
4498 /* Check for pending operations. */
4499
4500 267044 ulint count = 0;
4501
4502 do {
4503 267044 sp = get_space_by_id(space_id);
4504
4505 267044 count = space_check_pending_operations(sp, count);
4506
4507 267044 mutex_release();
4508
4509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
267044 if (count > 0) {
4510 std::this_thread::sleep_for(std::chrono::milliseconds(20));
4511 }
4512
4513 267044 mutex_acquire();
4514
4515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267044 times.
267044 } while (count > 0);
4516
4517 /* Check for pending IO. */
4518
4519 267044 *path = nullptr;
4520
4521 do {
4522 267561 sp = get_space_by_id(space_id);
4523
4524
2/2
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 267398 times.
267561 if (sp == nullptr) {
4525 163 mutex_release();
4526
4527 163 return DB_TABLESPACE_NOT_FOUND;
4528 }
4529
4530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267398 times.
267398 ut_a(sp->files.size() == 1);
4531 267398 const fil_node_t &file = sp->files.front();
4532
4533 267398 count = check_pending_io(sp, file, count);
4534
4535
2/2
✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 517 times.
267398 if (count == 0) {
4536 266881 *path = mem_strdup(file.name);
4537 }
4538
4539 267398 mutex_release();
4540
4541
2/2
✓ Branch 0 taken 266881 times.
✓ Branch 1 taken 517 times.
267398 if (count == 0) {
4542 266881 break;
4543 }
4544
4545
1/2
✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
517 std::this_thread::sleep_for(std::chrono::milliseconds(20));
4546 517 mutex_acquire();
4547
4548
1/2
✓ Branch 0 taken 517 times.
✗ Branch 1 not taken.
517 } while (count > 0);
4549
4550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266881 times.
266881 ut_ad(sp != nullptr);
4551
4552 266881 space = sp;
4553
4554 266881 return DB_SUCCESS;
4555 }
4556
4557 2912 std::string Fil_path::get_existing_path(const std::string &path,
4558 std::string &ghost) {
4559 2912 std::string existing_path{path};
4560
4561 /* This is only called for non-existing paths. */
4562
3/4
✓ Branch 0 taken 6599 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3687 times.
✓ Branch 3 taken 2912 times.
6599 while (!os_file_exists(existing_path.c_str())) {
4563 /* Some part of this path does not exist.
4564 If the last char is a separator, strip it off. */
4565
1/2
✓ Branch 0 taken 3687 times.
✗ Branch 1 not taken.
3687 trim_separator(existing_path);
4566
4567 3687 auto sep = existing_path.find_last_of(SEPARATOR);
4568
2/2
✓ Branch 0 taken 1260 times.
✓ Branch 1 taken 2427 times.
3687 if (sep == std::string::npos) {
4569 /* If no separator is found, it must be relative to the current dir. */
4570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1260 times.
1260 if (existing_path == ".") {
4571 /* This probably cannot happen, but break here to ensure that the
4572 loop always has a way out. */
4573 break;
4574 }
4575
1/2
✓ Branch 0 taken 1260 times.
✗ Branch 1 not taken.
1260 ghost.assign(path);
4576
1/2
✓ Branch 0 taken 1260 times.
✗ Branch 1 not taken.
1260 existing_path.assign(".");
4577
1/2
✓ Branch 0 taken 1260 times.
✗ Branch 1 not taken.
1260 existing_path.push_back(OS_SEPARATOR);
4578 } else {
4579
1/2
✓ Branch 0 taken 2427 times.
✗ Branch 1 not taken.
2427 ghost.assign(path.substr(sep + 1, path.length()));
4580
1/2
✓ Branch 0 taken 2427 times.
✗ Branch 1 not taken.
2427 existing_path.resize(sep + 1);
4581 }
4582 }
4583
4584 2912 return existing_path;
4585 }
4586
4587 871344 std::string Fil_path::get_real_path(const std::string &path, bool force) {
4588 bool path_exists;
4589 os_file_type_t path_type;
4590 char abspath[OS_FILE_MAX_PATH];
4591
1/2
✓ Branch 0 taken 871344 times.
✗ Branch 1 not taken.
871344 std::string in_path{path};
4592 871344 std::string real_path;
4593
4594
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 871343 times.
871344 if (path.empty()) {
4595
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 return std::string("");
4596 }
4597
4598 /* We do not need a separator at the end in order to determine what
4599 kind of object it is. So take it off. If it is there and the last
4600 part is actually a file, the correct real path will be returned. */
4601
6/6
✓ Branch 0 taken 851293 times.
✓ Branch 1 taken 20050 times.
✓ Branch 2 taken 215263 times.
✓ Branch 3 taken 636030 times.
✓ Branch 4 taken 215263 times.
✓ Branch 5 taken 656080 times.
871343 if (in_path.length() > 1 && is_separator(in_path.back())) {
4602
1/2
✓ Branch 0 taken 215263 times.
✗ Branch 1 not taken.
215263 trim_separator(in_path);
4603 }
4604
4605 /* Before we make an absolute path, check if this path exists,
4606 and if so, what type it is. */
4607
1/2
✓ Branch 0 taken 871343 times.
✗ Branch 1 not taken.
871343 os_file_status(in_path.c_str(), &path_exists, &path_type);
4608
4609
1/2
✓ Branch 0 taken 871343 times.
✗ Branch 1 not taken.
871343 int ret = my_realpath(abspath, in_path.c_str(), MYF(0));
4610
4611
2/2
✓ Branch 0 taken 868449 times.
✓ Branch 1 taken 2894 times.
871343 if (ret == 0) {
4612
1/2
✓ Branch 0 taken 868449 times.
✗ Branch 1 not taken.
868449 real_path.assign(abspath);
4613 } else {
4614 /* This often happens on non-Windows platforms when the path does not
4615 fully exist yet. */
4616
4617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2894 times.
2894 if (path_exists) {
4618 /* my_realpath() failed for some reason other than the path does not
4619 exist. */
4620 if (force) {
4621 /* Use the given path and make it comparable. */
4622 real_path.assign(in_path);
4623 } else {
4624 /* Return null and make a note of it. Another attempt will be made
4625 later when Fil_path::get_real_path() is called with force=true. */
4626 ib::info(ER_IB_MSG_289) << "my_realpath('" << path
4627 << "') failed for path type " << path_type;
4628 return (std::string(""));
4629 }
4630 } else {
4631 /* The path does not exist. Try my_realpath() again with the
4632 existing portion of the path. */
4633 2894 std::string ghost;
4634
1/2
✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
2894 std::string dir = get_existing_path(in_path, ghost);
4635
4636
1/2
✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
2894 ret = my_realpath(abspath, dir.c_str(), MYF(0));
4637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2894 times.
2894 ut_ad(ret == 0);
4638
4639 /* Concatenate the absolute path with the non-existing sub-path.
4640 NOTE: If this path existed, my_realpath() would put a separator
4641 at the end if it is a directory. But since the ghost portion
4642 does not yet exist, we don't know if it is a dir or a file, so
4643 we cannot attach a trailing separator for a directory. So we
4644 trim them off in Fil_path::is_same_as() and is_ancestor(). */
4645
1/2
✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
2894 real_path.assign(abspath);
4646
1/2
✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
2894 append_separator(real_path);
4647
1/2
✓ Branch 0 taken 2894 times.
✗ Branch 1 not taken.
2894 real_path.append(ghost);
4648 2894 }
4649 }
4650
4651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 871343 times.
871343 if (lower_case_file_system) {
4652 Fil_path::to_lower(real_path);
4653 }
4654
4655 /* Try to consistently end a directory name with a separator.
4656 On Windows, my_realpath() usually puts a separator at the end
4657 of a directory path (it does not do that for the path ".").
4658 On non-Windows it never does.
4659 So if the separator is missing, decide whether to append it. */
4660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 871343 times.
871343 ut_ad(!real_path.empty());
4661
2/2
✓ Branch 0 taken 871339 times.
✓ Branch 1 taken 4 times.
871343 if (!is_separator(real_path.back())) {
4662 871339 bool add_sep = true;
4663
3/4
✓ Branch 0 taken 234910 times.
✓ Branch 1 taken 633537 times.
✓ Branch 2 taken 2892 times.
✗ Branch 3 not taken.
871339 switch (path_type) {
4664 234910 case OS_FILE_TYPE_DIR:
4665 case OS_FILE_TYPE_BLOCK:
4666 234910 break;
4667 633537 case OS_FILE_TYPE_FILE:
4668 case OS_FILE_TYPE_LINK:
4669 633537 add_sep = false;
4670 633537 break;
4671 2892 case OS_FILE_TYPE_FAILED:
4672 case OS_FILE_TYPE_MISSING:
4673 case OS_FILE_TYPE_NAME_TOO_LONG:
4674 case OS_FILE_PERMISSION_ERROR:
4675 case OS_FILE_TYPE_UNKNOWN:
4676 /* This filepath is missing or cannot be identified for some other
4677 reason. If it ends in a three letter extension, assume it is a file
4678 name and do not add the trailing separator. Otherwise, assume it is
4679 intended to be a directory.*/
4680 2892 size_t s = real_path.size();
4681
5/8
✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2005 times.
✓ Branch 3 taken 887 times.
✓ Branch 4 taken 2005 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2005 times.
✗ Branch 7 not taken.
2892 if (s > 4 && real_path[s - 4] == '.' && real_path[s - 3] != '.' &&
4682
5/8
✓ Branch 0 taken 2005 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1969 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 1969 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1969 times.
✗ Branch 7 not taken.
2005 real_path[s - 2] != '.' && real_path[s - 1] != '.' &&
4683
5/8
✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1969 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1969 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1929 times.
✓ Branch 7 taken 963 times.
7753 !is_separator(real_path[s - 3]) &&
4684
3/4
✓ Branch 0 taken 1969 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1929 times.
✓ Branch 3 taken 40 times.
1969 !is_separator(real_path[s - 2])) {
4685 1929 add_sep = false;
4686 }
4687 }
4688
4689
2/2
✓ Branch 0 taken 235873 times.
✓ Branch 1 taken 635466 times.
871339 if (add_sep) {
4690
1/2
✓ Branch 0 taken 235873 times.
✗ Branch 1 not taken.
235873 append_separator(real_path);
4691 }
4692 }
4693
4694 871343 return real_path;
4695 871344 }
4696
4697 1885213 std::string Fil_path::get_basename(const std::string &filepath) {
4698 1885213 auto sep = filepath.find_last_of(SEPARATOR);
4699
4700 return (sep == std::string::npos)
4701 ? filepath
4702
2/2
✓ Branch 0 taken 353431 times.
✓ Branch 1 taken 1531782 times.
1885213 : filepath.substr(sep + 1, filepath.length() - sep);
4703 }
4704
4705 /** Constructor
4706 @param[in] dir Directory that the files are under */
4707 9887 Tablespace_files::Tablespace_files(const std::string &dir)
4708
1/2
✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
9887 : m_ibd_paths(), m_undo_paths(), m_dir(dir) {
4709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9887 times.
9887 ut_ad(Fil_path::is_separator(dir.back()));
4710 9887 }
4711
4712 /** Closes a single-table tablespace. The tablespace must be cached in the
4713 memory cache. Free all pages used by the tablespace.
4714 @param[in] space_id Tablespace ID
4715 @return DB_SUCCESS or error */
4716 308 dberr_t fil_close_tablespace(space_id_t space_id) {
4717
2/4
✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 308 times.
308 ut_ad(!fsp_is_undo_tablespace(space_id));
4718
2/4
✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 308 times.
308 ut_ad(!fsp_is_system_or_temp_tablespace(space_id));
4719
4720
1/2
✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
308 auto shard = fil_system->shard_by_id(space_id);
4721
4722 308 char *path{};
4723 308 fil_space_t *space{};
4724
4725
1/2
✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
308 auto err = shard->wait_for_pending_operations(space_id, space, &path);
4726
4727
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 181 times.
308 if (err != DB_SUCCESS) {
4728 127 return err;
4729 }
4730
4731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
181 ut_a(path != nullptr);
4732
4733 #ifndef UNIV_HOTBACKUP
4734 181 shard->space_prepare_for_delete(space);
4735 #else
4736 rw_lock_x_lock(&space->latch, UT_LOCATION_HERE);
4737
4738 /* If the free is successful, the X lock will be released before
4739 the space memory data structure is freed. */
4740
4741 if (!fil_space_free(space_id, true)) {
4742 rw_lock_x_unlock(&space->latch);
4743 err = DB_TABLESPACE_NOT_FOUND;
4744 } else {
4745 err = DB_SUCCESS;
4746 }
4747 #endif /* !UNIV_HOTBACKUP */
4748
4749 /* Delete any generated files, otherwise if we drop the database the
4750 remove directory will fail. */
4751
4752
2/4
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181 times.
✗ Branch 3 not taken.
181 auto cfg_name = Fil_path::make_cfg(path);
4753
4754
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 if (cfg_name != nullptr) {
4755
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 os_file_delete_if_exists(innodb_data_file_key, cfg_name, nullptr);
4756
4757 181 ut::free(cfg_name);
4758 }
4759
4760
2/4
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 181 times.
✗ Branch 3 not taken.
181 auto cfp_name = Fil_path::make_cfp(path);
4761
4762
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 if (cfp_name != nullptr) {
4763
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 os_file_delete_if_exists(innodb_data_file_key, cfp_name, nullptr);
4764
4765 181 ut::free(cfp_name);
4766 }
4767
4768 181 ut::free(path);
4769
4770 181 return err;
4771 }
4772
4773 #ifndef UNIV_HOTBACKUP
4774 /** Write a log record about an operation on a tablespace file.
4775 @param[in] type MLOG_FILE_OPEN or MLOG_FILE_DELETE
4776 or MLOG_FILE_CREATE or MLOG_FILE_RENAME
4777 @param[in] space_id Tablespace identifier
4778 @param[in] path File path
4779 @param[in] new_path If type is MLOG_FILE_RENAME, the new name
4780 @param[in] flags If type is MLOG_FILE_CREATE, the space flags
4781 @param[in,out] mtr Mini-transaction */
4782 464691 static void fil_op_write_log(mlog_id_t type, space_id_t space_id,
4783 const char *path, const char *new_path,
4784 uint32_t flags, mtr_t *mtr) {
4785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 464691 times.
464691 ut_ad(space_id != TRX_SYS_SPACE);
4786
4787 464691 byte *log_ptr = nullptr;
4788
4789
3/4
✓ Branch 0 taken 464691 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 538 times.
✓ Branch 3 taken 464153 times.
464691 if (!mlog_open(mtr, 11 + 4 + 2 + 1, log_ptr)) {
4790 /* Logging in mtr is switched off during crash recovery:
4791 in that case mlog_open returns nullptr */
4792 538 return;
4793 }
4794
4795
1/2
✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
464153 log_ptr = mlog_write_initial_log_record_low(type, space_id, 0, log_ptr, mtr);
4796
4797
2/2
✓ Branch 0 taken 197471 times.
✓ Branch 1 taken 266682 times.
464153 if (type == MLOG_FILE_CREATE) {
4798
1/2
✓ Branch 0 taken 197471 times.
✗ Branch 1 not taken.
197471 mach_write_to_4(log_ptr, flags);
4799 197471 log_ptr += 4;
4800 }
4801
4802 /* Let us store the strings as null-terminated for easier readability
4803 and handling */
4804
4805 464153 ulint len = strlen(path) + 1;
4806
4807
1/2
✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
464153 mach_write_to_2(log_ptr, len);
4808 464153 log_ptr += 2;
4809
4810
1/2
✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
464153 mlog_close(mtr, log_ptr);
4811
4812
1/2
✓ Branch 0 taken 464153 times.
✗ Branch 1 not taken.
464153 mlog_catenate_string(mtr, reinterpret_cast<const byte *>(path), len);
4813
4814
2/3
✓ Branch 0 taken 79539 times.
✓ Branch 1 taken 384614 times.
✗ Branch 2 not taken.
464153 switch (type) {
4815 79539 case MLOG_FILE_RENAME:
4816
4817
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79539 times.
79539 ut_ad(strchr(new_path, Fil_path::OS_SEPARATOR) != nullptr);
4818
4819 79539 len = strlen(new_path) + 1;
4820
4821
2/4
✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79539 times.
79539 ut_a(mlog_open(mtr, 2 + len, log_ptr));
4822
4823
1/2
✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
79539 mach_write_to_2(log_ptr, len);
4824
4825 79539 log_ptr += 2;
4826
4827
1/2
✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
79539 mlog_close(mtr, log_ptr);
4828
4829
1/2
✓ Branch 0 taken 79539 times.
✗ Branch 1 not taken.
79539 mlog_catenate_string(mtr, reinterpret_cast<const byte *>(new_path), len);
4830 79539 break;
4831 384614 case MLOG_FILE_DELETE:
4832 case MLOG_FILE_CREATE:
4833 384614 break;
4834 default:
4835 ut_d(ut_error);
4836 }
4837 }
4838
4839 4 bool fil_system_get_file_by_space_id(space_id_t space_id, std::string &name) {
4840
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 ut_a(dict_sys_t::is_reserved(space_id) || srv_is_upgrade_mode);
4841
4842 4 return fil_system->get_file_by_space_id(space_id, name);
4843 }
4844
4845 1196733 bool fil_system_get_file_by_space_num(space_id_t space_num,
4846 space_id_t &space_id, std::string &name) {
4847 1196733 return fil_system->get_file_by_space_num(space_num, space_id, name);
4848 }
4849
4850 #endif /* !UNIV_HOTBACKUP */
4851
4852 187361 dberr_t Fil_shard::space_delete(space_id_t space_id, buf_remove_t buf_remove) {
4853 187361 char *path = nullptr;
4854 187361 fil_space_t *space = nullptr;
4855
4856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187361 times.
187361 ut_ad(!fsp_is_system_tablespace(space_id));
4857
2/4
✓ Branch 0 taken 187361 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187361 times.
187361 ut_ad(!fsp_is_global_temporary(space_id));
4858
4859
1/2
✓ Branch 0 taken 187361 times.
✗ Branch 1 not taken.
187361 dberr_t err = wait_for_pending_operations(space_id, space, &path);
4860
4861
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 187325 times.
187361 if (err != DB_SUCCESS) {
4862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 ut_a(err == DB_TABLESPACE_NOT_FOUND);
4863 36 return err;
4864 }
4865
4866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187325 times.
187325 ut_a(path != nullptr);
4867
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187325 times.
187325 ut_a(space != nullptr);
4868
4869 #ifndef UNIV_HOTBACKUP
4870 /* IMPORTANT: Because we have set space::stop_new_ops there
4871 can't be any new ibuf merges, reads or flushes. We are here
4872 because file::n_pending was zero above. However, it is still
4873 possible to have pending read and write requests:
4874
4875 A read request can happen because the reader thread has
4876 gone through the ::stop_new_ops check in buf_page_init_for_read()
4877 before the flag was set and has not yet incremented ::n_pending
4878 when we checked it above.
4879
4880 A write request can be issued any time because we don't check
4881 the ::stop_new_ops flag when queueing a block for write.
4882
4883 We deal with pending write requests in the following function
4884 where we'd minimally evict all dirty pages belonging to this
4885 space from the flush_list. Note that if a block is IO-fixed
4886 we'll wait for IO to complete.
4887
4888 For buf_remove == BUF_REMOVE_NONE we mark the fil_space_t instance
4889 as deleted by bumping up the file_space_t::m_version. All pages
4890 that are less than this version number will be discarded. We wait
4891 for any pending IO to complete after that.
4892
4893 To deal with potential read requests, we will check the
4894 ::stop_new_ops flag in fil_io(). */
4895
4896
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 187323 times.
187325 if (buf_remove != BUF_REMOVE_NONE) {
4897
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 buf_LRU_flush_or_remove_pages(space_id, buf_remove, nullptr);
4898 }
4899
4900 /* Ensure that we write redo log for the operation also within the Clone
4901 notifier block. This is needed because we don't have any mechanism today
4902 to avoid checkpoint crossing the redo log before the actual operation
4903 is complete. Make sure we are not holding shard mutex. */
4904
2/4
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187325 times.
187325 ut_ad(!mutex_owned());
4905
1/2
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
187325 Clone_notify notifier(Clone_notify::Type::SPACE_DROP, space_id, false);
4906
4907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187325 times.
187325 if (notifier.failed()) {
4908 /* Currently post DDL operations are never rolled back. */
4909 /* purecov: begin deadcode */
4910 ut::free(path);
4911 ut_d(ut_error);
4912 ut_o(return DB_ERROR);
4913 /* purecov: end */
4914 }
4915 #endif /* !UNIV_HOTBACKUP */
4916
4917 /* If it is a delete then also delete any generated files, otherwise
4918 when we drop the database the remove directory will fail. */
4919
1/2
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
187325 if (space->purpose != FIL_TYPE_TEMPORARY) {
4920 #ifdef UNIV_HOTBACKUP
4921 /* When replaying the operation in MySQL Enterprise
4922 Backup, we do not try to write any log record. */
4923 #else /* UNIV_HOTBACKUP */
4924 /* Before deleting the file, write a log record about it, so that
4925 InnoDB crash recovery will expect the file to be gone. */
4926
1/2
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
187325 mtr_t mtr;
4927
4928
1/2
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
187325 mtr.start();
4929
4930
1/2
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
187325 fil_op_write_log(MLOG_FILE_DELETE, space_id, path, nullptr, 0, &mtr);
4931
4932
1/2
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
187325 mtr.commit();
4933
4934
5/8
✓ Branch 0 taken 187325 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 187324 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
187325 DBUG_EXECUTE_IF("delete_crash", log_buffer_flush_to_disk();
4935 DBUG_SUICIDE(););
4936
4937 /* Even if we got killed shortly after deleting the
4938 tablespace file, the record must have already been
4939 written to the redo log. */
4940
2/4
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
187324 log_write_up_to(*log_sys, mtr.commit_lsn(), true);
4941 #endif /* UNIV_HOTBACKUP */
4942
4943
2/4
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
187324 char *cfg_name = Fil_path::make_cfg(path);
4944
4945
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 if (cfg_name != nullptr) {
4946
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 os_file_delete_if_exists(innodb_data_file_key, cfg_name, nullptr);
4947
4948 187324 ut::free(cfg_name);
4949 }
4950
4951
2/4
✓ Branch 0 taken 187323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
187324 char *cfp_name = Fil_path::make_cfp(path);
4952
4953
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 if (cfp_name != nullptr) {
4954
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 os_file_delete_if_exists(innodb_data_file_key, cfp_name, nullptr);
4955
4956 187324 ut::free(cfp_name);
4957 }
4958 187324 }
4959
4960
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 mutex_acquire();
4961
4962 /* Double check the sanity of pending ops after reacquiring
4963 the fil_system::mutex. */
4964
2/4
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187324 times.
✗ Branch 3 not taken.
187324 if (const fil_space_t *s = get_space_by_id(space_id)) {
4965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
187324 ut_a(s == space);
4966
4967
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 space->set_deleted();
4968
4969 #ifndef UNIV_HOTBACKUP
4970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
187324 ut_a(space->files.size() == 1);
4971 187324 auto &file = space->files.front();
4972
4973 /* Wait for any pending writes. */
4974
3/4
✓ Branch 0 taken 167823 times.
✓ Branch 1 taken 187324 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 187324 times.
355147 while (file.n_pending_ios > 0 || file.n_pending_flushes > 0 ||
4975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
187324 file.is_being_extended) {
4976 /* Release and reacquire the mutex because we want the IO to complete. */
4977
1/2
✓ Branch 0 taken 167823 times.
✗ Branch 1 not taken.
167823 mutex_release();
4978
4979 167823 std::this_thread::yield();
4980
4981
1/2
✓ Branch 0 taken 167823 times.
✗ Branch 1 not taken.
167823 mutex_acquire();
4982 }
4983
4984
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 m_deleted_spaces.push_back({space->id, space});
4985 #endif /* !UNIV_HOTBACKUP */
4986
4987
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187324 space_detach(space);
4988
4989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
187324 ut_a(space->files.size() == 1);
4990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187324 times.
187324 ut_a(space->files.front().n_pending_ios == 0);
4991
1/2
✓ Branch 0 taken 187323 times.
✗ Branch 1 not taken.
187324 space_remove_from_lookup_maps(space_id);
4992
4993
1/2
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
187323 mutex_release();
4994
4995 #ifdef UNIV_HOTBACKUP
4996 /* For usage inside MEB we don't support lazy stale page eviction, we just
4997 do what fil_shard::purge() does directly here. */
4998 space_free_low(space);
4999 #endif /* UNIV_HOTBACKUP */
5000
5001
3/6
✓ Branch 0 taken 187324 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 187324 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 187324 times.
187324 if (!os_file_delete(innodb_data_file_key, path) &&
5002 !os_file_delete_if_exists(innodb_data_file_key, path, nullptr)) {
5003 /* Note: This is because we have removed the
5004 tablespace instance from the cache. */
5005
5006 err = DB_IO_ERROR;
5007 }
5008 } else {
5009 mutex_release();
5010
5011 err = DB_TABLESPACE_NOT_FOUND;
5012 }
5013
5014 187324 ut::free(path);
5015 187324 return err;
5016 187324 }
5017
5018 187361 dberr_t fil_delete_tablespace(space_id_t space_id, buf_remove_t buf_remove) {
5019 187361 auto shard = fil_system->shard_by_id(space_id);
5020
5021 187361 return shard->space_delete(space_id, buf_remove);
5022 }
5023
5024 79375 dberr_t Fil_shard::space_prepare_for_truncate(space_id_t space_id,
5025 fil_space_t *&space) {
5026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79375 times.
79375 ut_ad(space_id != TRX_SYS_SPACE);
5027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79375 times.
79375 ut_ad(!fsp_is_system_tablespace(space_id));
5028
2/4
✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79375 times.
79375 ut_ad(!fsp_is_global_temporary(space_id));
5029
5030 79375 char *path{};
5031
1/2
✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
79375 auto err = wait_for_pending_operations(space_id, space, &path);
5032
5033 79375 ut::free(path);
5034
5035 79375 return err;
5036 }
5037
5038 79375 bool Fil_shard::space_truncate(space_id_t space_id, page_no_t size_in_pages) {
5039 #ifndef UNIV_HOTBACKUP
5040 79375 fil_space_t *space{};
5041
5042 /* Step-1: Prepare tablespace for truncate. This involves
5043 stopping all the new operations + IO on that tablespace. Any future attempts
5044 to flush will be ignored and pages discarded. */
5045
2/4
✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79375 times.
79375 if (space_prepare_for_truncate(space_id, space) != DB_SUCCESS) {
5046 return false;
5047 }
5048
5049
1/2
✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
79375 mutex_acquire();
5050
5051 /* Step-2: Mark the tablespace pages in the buffer pool as stale by bumping
5052 the version number of the space. Those stale pages will be ignored and freed
5053 lazily later. This includes AHI, for which entries will be removed on
5054 buf_page_free_stale*() -> buf_LRU_free_page ->
5055 btr_search_drop_page_hash_index() */
5056
1/2
✓ Branch 0 taken 79375 times.
✗ Branch 1 not taken.
79375 space->bump_version();
5057
5058 /* Step-3: Truncate the tablespace and accordingly update
5059 the fil_space_t handler that is used to access this tablespace. */
5060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79375 times.
79375 ut_a(space->files.size() == 1);
5061
5062 79375 auto &file = space->files.front();
5063
5064
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 79353 times.
79375 if (!file.is_open) {
5065
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (!open_file(&file)) {
5066 mutex_release();
5067 return false;
5068 }
5069 }
5070
5071 79375 space->size = file.size = size_in_pages;
5072
5073
1/2
✓ Branch 0 taken 79373 times.
✗ Branch 1 not taken.
79375 bool success = os_file_truncate(file.name, file.handle, 0);
5074
5075
1/2
✓ Branch 0 taken 79374 times.
✗ Branch 1 not taken.
79373 if (success) {
5076 79374 os_offset_t size = size_in_pages * UNIV_PAGE_SIZE;
5077
5078
1/2
✓ Branch 0 taken 79371 times.
✗ Branch 1 not taken.
79374 success = os_file_set_size(file.name, file.handle, 0, size, true);
5079
5080
1/2
✓ Branch 0 taken 79371 times.
✗ Branch 1 not taken.
79371 if (success) {
5081 79371 space->stop_new_ops = false;
5082 }
5083 }
5084
5085
1/2
✓ Branch 0 taken 79373 times.
✗ Branch 1 not taken.
79370 mutex_release();
5086
5087 79373 return success;
5088 #else
5089 /* Truncating a tablespace is not supported for MEB. */
5090 ut_error;
5091 #endif
5092 }
5093
5094 /** Truncate the tablespace to needed size.
5095 @param[in] space_id Tablespace ID to truncate
5096 @param[in] size_in_pages Truncate size.
5097 @return true if truncate was successful. */
5098 79375 bool fil_truncate_tablespace(space_id_t space_id, page_no_t size_in_pages) {
5099 79375 auto shard = fil_system->shard_by_id(space_id);
5100
5101 79375 return shard->space_truncate(space_id, size_in_pages);
5102 }
5103
5104 #ifdef UNIV_DEBUG
5105 /** Increase redo skipped count for a tablespace.
5106 @param[in] space_id Tablespace ID */
5107 54672 void fil_space_inc_redo_skipped_count(space_id_t space_id) {
5108 54672 auto shard = fil_system->shard_by_id(space_id);
5109
5110 54671 shard->mutex_acquire();
5111
5112 54671 fil_space_t *space = shard->get_space_by_id(space_id);
5113
5114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54672 times.
54673 ut_a(space != nullptr);
5115
5116 54672 ++space->redo_skipped_count;
5117
5118 54672 shard->mutex_release();
5119 54671 }
5120
5121 /** Decrease redo skipped count for a tablespace.
5122 @param[in] space_id Tablespace ID */
5123 54673 void fil_space_dec_redo_skipped_count(space_id_t space_id) {
5124 54673 auto shard = fil_system->shard_by_id(space_id);
5125
5126 54673 shard->mutex_acquire();
5127
5128 54673 fil_space_t *space = shard->get_space_by_id(space_id);
5129
5130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54673 times.
54673 ut_a(space != nullptr);
5131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54673 times.
54673 ut_a(space->redo_skipped_count > 0);
5132
5133 54673 --space->redo_skipped_count;
5134
5135 54673 shard->mutex_release();
5136 54673 }
5137
5138 /** Check whether a single-table tablespace is redo skipped.
5139 @param[in] space_id Tablespace ID
5140 @return true if redo skipped */
5141 129510 bool fil_space_is_redo_skipped(space_id_t space_id) {
5142 129510 auto shard = fil_system->shard_by_id(space_id);
5143
5144 129510 shard->mutex_acquire();
5145
5146 129510 fil_space_t *space = shard->get_space_by_id(space_id);
5147
5148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129510 times.
129510 ut_a(space != nullptr);
5149
5150 129510 bool is_redo_skipped = space->redo_skipped_count > 0;
5151
5152 129510 shard->mutex_release();
5153
5154 129510 return is_redo_skipped;
5155 }
5156 #endif /* UNIV_DEBUG */
5157
5158 #ifndef UNIV_HOTBACKUP
5159
5160 /** Discards a single-table tablespace. The tablespace must be cached in the
5161 memory cache. Discarding is like deleting a tablespace, but
5162
5163 1. We do not drop the table from the data dictionary;
5164
5165 2. We remove all insert buffer entries for the tablespace immediately;
5166 in DROP TABLE they are only removed gradually in the background;
5167
5168 3. When the user does IMPORT TABLESPACE, the tablespace will have the
5169 same id as it originally had.
5170
5171 4. Free all the pages in use by the tablespace if rename=true.
5172 @param[in] space_id Tablespace ID
5173 @return DB_SUCCESS or error */
5174 765 dberr_t fil_discard_tablespace(space_id_t space_id) {
5175 dberr_t err;
5176
5177 765 err = fil_delete_tablespace(space_id, BUF_REMOVE_NONE);
5178
5179
2/4
✓ Branch 0 taken 749 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
765 switch (err) {
5180 749 case DB_SUCCESS:
5181 749 break;
5182
5183 case DB_IO_ERROR:
5184
5185 ib::warn(ER_IB_MSG_291, ulong{space_id}, ut_strerr(err));
5186 break;
5187
5188 16 case DB_TABLESPACE_NOT_FOUND:
5189
5190
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 ib::warn(ER_IB_MSG_292, ulong{space_id}, ut_strerr(err));
5191 16 break;
5192
5193 default:
5194 ut_error;
5195 }
5196
5197 765 return err;
5198 }
5199
5200 /** Write redo log for renaming a file.
5201 @param[in] space_id Tablespace id
5202 @param[in] old_name Tablespace file name
5203 @param[in] new_name Tablespace file name after renaming
5204 @param[in,out] mtr Mini-transaction */
5205 79718 static void fil_name_write_rename(space_id_t space_id, const char *old_name,
5206 const char *new_name, mtr_t *mtr) {
5207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79718 times.
79718 ut_ad(!fsp_is_system_or_temp_tablespace(space_id));
5208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79718 times.
79718 ut_ad(!fsp_is_undo_tablespace(space_id));
5209
5210 /* Note: A checkpoint can take place here. */
5211
5212
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 79717 times.
79718 DBUG_EXECUTE_IF("ib_crash_rename_log_1", DBUG_SUICIDE(););
5213
5214 static const auto type = MLOG_FILE_RENAME;
5215
5216 79717 fil_op_write_log(type, space_id, old_name, new_name, 0, mtr);
5217
5218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
79717 DBUG_EXECUTE_IF("ib_crash_rename_log_2", DBUG_SUICIDE(););
5219
5220 /* Note: A checkpoint can take place here too before we
5221 have physically renamed the file. */
5222 79717 }
5223
5224 #ifdef UNIV_LINUX
5225 /* Write a redo log record for adding pages to a tablespace
5226 @param[in] space_id Space ID
5227 @param[in] offset Offset from where the file
5228 is extended
5229 @param[in] size Number of bytes by which the file
5230 is extended starting from the offset
5231 @param[in,out] mtr Mini-transaction */
5232 183399 static void fil_op_write_space_extend(space_id_t space_id, os_offset_t offset,
5233 os_offset_t size, mtr_t *mtr) {
5234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183399 times.
183399 ut_ad(space_id != TRX_SYS_SPACE);
5235
5236 byte *log_ptr;
5237
5238
3/4
✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 366 times.
✓ Branch 3 taken 183033 times.
183399 if (!mlog_open(mtr, 7 + 8 + 8, log_ptr)) {
5239 /* Logging in mtr is switched off during crash recovery:
5240 in that case mlog_open returns nullptr */
5241 366 return;
5242 }
5243
5244 #ifdef UNIV_DEBUG
5245 183033 byte *start_log = log_ptr;
5246 #endif /* UNIV_DEBUG */
5247
5248
1/2
✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
183033 log_ptr = mlog_write_initial_log_record_low(MLOG_FILE_EXTEND, space_id, 0,
5249 log_ptr, mtr);
5250
5251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183033 times.
183033 ut_ad(size > 0);
5252
5253 /* Write the starting offset in the file */
5254
1/2
✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
183033 mach_write_to_8(log_ptr, offset);
5255 183033 log_ptr += 8;
5256
5257 /* Write the size by which file needs to be extended from
5258 the given offset */
5259
1/2
✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
183033 mach_write_to_8(log_ptr, size);
5260 183033 log_ptr += 8;
5261
5262 #ifdef UNIV_DEBUG
5263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183033 times.
183033 ut_ad(log_ptr <= start_log + 23);
5264 #endif /* UNIV_DEBUG */
5265
5266
1/2
✓ Branch 0 taken 183033 times.
✗ Branch 1 not taken.
183033 mlog_close(mtr, log_ptr);
5267 }
5268 #endif
5269 #endif /* !UNIV_HOTBACKUP */
5270
5271 /** Allocate and build a file name from a path, a table or tablespace name
5272 and a suffix.
5273 @param[in] path_in nullptr or the direcory path or the full path
5274 and filename
5275 @param[in] name_in nullptr if path is full, or Table/Tablespace
5276 name
5277 @param[in] ext the file extension to use
5278 @param[in] trim whether last name on the path should be trimmed
5279 @return own: file name; must be freed by ut::free() */
5280 1037829 char *Fil_path::make(const std::string &path_in, const std::string &name_in,
5281 ib_file_suffix ext, bool trim) {
5282 /* The path should be a directory and should not contain the
5283 basename of the file. If the path is empty, we will use the
5284 default path, */
5285
5286
4/6
✓ Branch 0 taken 621625 times.
✓ Branch 1 taken 416208 times.
✓ Branch 2 taken 621622 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1037830 times.
1037829 ut_ad(!path_in.empty() || !name_in.empty());
5287
5288 1037830 std::string path;
5289
5290
2/2
✓ Branch 0 taken 621622 times.
✓ Branch 1 taken 416208 times.
1037833 if (path_in.empty()) {
5291
2/4
✓ Branch 0 taken 621622 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 621622 times.
621622 if (is_absolute_path(name_in)) {
5292 path = "";
5293 } else {
5294
1/2
✓ Branch 0 taken 621622 times.
✗ Branch 1 not taken.
621622 path.assign(MySQL_datadir_path);
5295 }
5296 } else {
5297
1/2
✓ Branch 0 taken 416209 times.
✗ Branch 1 not taken.
416208 path.assign(path_in);
5298 }
5299
5300 1037831 std::string name;
5301
5302
2/2
✓ Branch 0 taken 662430 times.
✓ Branch 1 taken 375403 times.
1037833 if (!name_in.empty()) {
5303
1/2
✓ Branch 0 taken 662429 times.
✗ Branch 1 not taken.
662430 name.assign(name_in);
5304 }
5305
5306 /* Do not prepend the datadir path (which must be DOT_SLASH)
5307 if the name is an absolute path or a relative path like
5308 DOT_SLASH or DOT_DOT_SLASH. */
5309
11/18
✓ Branch 0 taken 1037832 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1037825 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1037829 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1037821 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1037813 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 1037823 times.
✓ Branch 11 taken 10 times.
✓ Branch 12 taken 16 times.
✓ Branch 13 taken 1037817 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
3113481 if (is_absolute_path(name) || has_prefix(name, DOT_SLASH) ||
5310
10/16
✓ Branch 0 taken 1037819 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1037817 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1037814 times.
✓ Branch 6 taken 1037817 times.
✓ Branch 7 taken 15 times.
✓ Branch 8 taken 1037817 times.
✓ Branch 9 taken 15 times.
✓ Branch 10 taken 1037827 times.
✓ Branch 11 taken 5 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
2075645 has_prefix(name, DOT_DOT_SLASH)) {
5311 16 path.clear();
5312 }
5313
5314 1037833 std::string filepath;
5315
5316
2/2
✓ Branch 0 taken 1037816 times.
✓ Branch 1 taken 16 times.
1037831 if (!path.empty()) {
5317
1/2
✓ Branch 0 taken 1037817 times.
✗ Branch 1 not taken.
1037816 filepath.assign(path);
5318 }
5319
5320
2/2
✓ Branch 0 taken 4219 times.
✓ Branch 1 taken 1033614 times.
1037833 if (trim) {
5321 /* Find the offset of the last DIR separator and set it to
5322 null in order to strip off the old basename from this path. */
5323 4219 auto pos = filepath.find_last_of(SEPARATOR);
5324
5325
1/2
✓ Branch 0 taken 4219 times.
✗ Branch 1 not taken.
4219 if (pos != std::string::npos) {
5326
1/2
✓ Branch 0 taken 4219 times.
✗ Branch 1 not taken.
4219 filepath.resize(pos);
5327 }
5328 }
5329
5330
2/2
✓ Branch 0 taken 662429 times.
✓ Branch 1 taken 375404 times.
1037833 if (!name.empty()) {
5331
1/2
✓ Branch 0 taken 662429 times.
✗ Branch 1 not taken.
662429 append_separator(filepath);
5332
5333
1/2
✓ Branch 0 taken 662428 times.
✗ Branch 1 not taken.
662429 filepath.append(name);
5334 }
5335
5336 /* Make sure that the specified suffix is at the end. */
5337
2/2
✓ Branch 0 taken 999129 times.
✓ Branch 1 taken 38703 times.
1037832 if (ext != NO_EXT) {
5338 999129 const auto suffix = dot_ext[ext];
5339 999129 size_t len = strlen(suffix);
5340
5341 /* This assumes that the suffix starts with '.'. If the
5342 first char of the suffix is found in the filepath at the
5343 same length as the suffix from the end, then we will assume
5344 that there is a previous suffix that needs to be replaced. */
5345
5346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 999129 times.
999129 ut_ad(*suffix == '.');
5347
5348
5/6
✓ Branch 0 taken 999129 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 376161 times.
✓ Branch 3 taken 622968 times.
✓ Branch 4 taken 376161 times.
✓ Branch 5 taken 622968 times.
999129 if (filepath.length() > len && *(filepath.end() - len) == *suffix) {
5349
1/2
✓ Branch 0 taken 376161 times.
✗ Branch 1 not taken.
376161 filepath.replace(filepath.end() - len, filepath.end(), suffix);
5350 } else {
5351
1/2
✓ Branch 0 taken 622968 times.
✗ Branch 1 not taken.
622968 filepath.append(suffix);
5352 }
5353 }
5354
5355 1037832 normalize(filepath);
5356
5357
1/2
✓ Branch 0 taken 1037832 times.
✗ Branch 1 not taken.
2075667 return mem_strdup(filepath.c_str());
5358 1037832 }
5359
5360 250511 bool Fil_path::parse_file_path(const std::string &file_path,
5361 ib_file_suffix extn, std::string &dict_name) {
5362
1/2
✓ Branch 0 taken 250511 times.
✗ Branch 1 not taken.
250511 dict_name.assign(file_path);
5363
3/4
✓ Branch 0 taken 250511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 498 times.
✓ Branch 3 taken 250013 times.
250511 if (!Fil_path::truncate_suffix(extn, dict_name)) {
5364 498 dict_name.clear();
5365 498 return false;
5366 }
5367
5368 /* Extract table name */
5369 250013 auto table_pos = dict_name.find_last_of(SEPARATOR);
5370
2/2
✓ Branch 0 taken 849 times.
✓ Branch 1 taken 249164 times.
250013 if (table_pos == std::string::npos) {
5371 849 dict_name.clear();
5372 849 return false;
5373 }
5374
1/2
✓ Branch 0 taken 249164 times.
✗ Branch 1 not taken.
249164 std::string table_name = dict_name.substr(table_pos + 1);
5375
1/2
✓ Branch 0 taken 249164 times.
✗ Branch 1 not taken.
249164 dict_name.resize(table_pos);
5376
5377 /* Extract schema name */
5378 249164 auto schema_pos = dict_name.find_last_of(SEPARATOR);
5379
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 249129 times.
249164 if (schema_pos == std::string::npos) {
5380 35 dict_name.clear();
5381 35 return false;
5382 }
5383
1/2
✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
249129 std::string schema_name = dict_name.substr(schema_pos + 1);
5384
5385 /* Build dictionary table name schema/table form. */
5386
1/2
✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
249129 dict_name.assign(schema_name);
5387
1/2
✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
249129 dict_name.push_back(DB_SEPARATOR);
5388
1/2
✓ Branch 0 taken 249129 times.
✗ Branch 1 not taken.
249129 dict_name.append(table_name);
5389 249129 return true;
5390 249164 }
5391
5392 56249 std::string Fil_path::make_new_path(const std::string &path_in,
5393 const std::string &name_in,
5394 ib_file_suffix extn) {
5395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
56249 ut_a(Fil_path::has_suffix(extn, path_in));
5396
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
56249 ut_a(!Fil_path::has_suffix(extn, name_in));
5397
5398 56249 std::string path(path_in);
5399
5400 56249 auto pos = path.find_last_of(SEPARATOR);
5401
5402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
56249 ut_a(pos != std::string::npos);
5403
5404
1/2
✓ Branch 0 taken 56249 times.
✗ Branch 1 not taken.
56249 path.resize(pos);
5405
5406 56249 pos = path.find_last_of(SEPARATOR);
5407
5408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56249 times.
56249 ut_a(pos != std::string::npos);
5409
5410
1/2
✓ Branch 0 taken 56249 times.
✗ Branch 1 not taken.
56249 path.resize(pos + 1);
5411
5412
2/4
✓ Branch 0 taken 56249 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56249 times.
✗ Branch 3 not taken.
56249 path.append(name_in + dot_ext[extn]);
5413
5414 56249 normalize(path);
5415
5416 56249 return path;
5417 }
5418
5419 /** This function reduces a null-terminated full remote path name
5420 into the path that is sent by MySQL for DATA DIRECTORY clause.
5421 It replaces the 'databasename/tablename.ibd' found at the end of the
5422 path with just 'tablename'.
5423
5424 Since the result is always smaller than the path sent in, no new
5425 memory is allocated. The caller should allocate memory for the path
5426 sent in. This function manipulates that path in place. If the path
5427 format is not as expected, set data_dir_path to "" and return.
5428
5429 The result is used to inform a SHOW CREATE TABLE command.
5430 @param[in,out] data_dir_path Full path/data_dir_path */
5431 208 void Fil_path::make_data_dir_path(char *data_dir_path) {
5432 /* Replace the period before the extension with a null byte. */
5433
3/6
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 208 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 208 times.
208 ut_ad(has_suffix(IBD, data_dir_path));
5434 208 char *dot = strrchr((char *)data_dir_path, '.');
5435 208 *dot = '\0';
5436
5437 /* The tablename starts after the last slash. */
5438 208 char *base_slash = strrchr((char *)data_dir_path, OS_PATH_SEPARATOR);
5439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 ut_ad(base_slash != nullptr);
5440
5441 208 *base_slash = '\0';
5442
5443
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 std::string base_name{base_slash + 1};
5444
5445 /* The database name starts after the next to last slash. */
5446 208 char *db_slash = strrchr((char *)data_dir_path, OS_SEPARATOR);
5447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 ut_ad(db_slash != nullptr);
5448 208 char *db_name = db_slash + 1;
5449
5450 /* Overwrite the db_name with the base_name. */
5451 208 memmove(db_name, base_name.c_str(), base_name.length());
5452 208 db_name[base_name.length()] = '\0';
5453 208 }
5454
5455 /** Test if a tablespace file can be renamed to a new filepath by checking
5456 if that the old filepath exists and the new filepath does not exist.
5457 @param[in] space_id Tablespace ID
5458 @param[in] old_path Old filepath
5459 @param[in] new_path New filepath
5460 @param[in] is_discarded Whether the tablespace is discarded
5461 @return innodb error code */
5462 101909 dberr_t fil_rename_tablespace_check(space_id_t space_id, const char *old_path,
5463 const char *new_path, bool is_discarded) {
5464 bool exists;
5465 os_file_type_t ftype;
5466
5467
6/10
✓ Branch 0 taken 101905 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 101905 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 101905 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 101905 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 101909 times.
101909 if (!is_discarded && os_file_status(old_path, &exists, &ftype) && !exists) {
5468 ib::error(ER_IB_MSG_293, old_path, new_path, ulong{space_id});
5469 return DB_TABLESPACE_NOT_FOUND;
5470 }
5471
5472
6/8
✓ Branch 0 taken 101909 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 101909 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 101898 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 101898 times.
101909 if (!os_file_status(new_path, &exists, &ftype) || exists) {
5473
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 ib::error(ER_IB_MSG_294, old_path, new_path, ulong{space_id});
5474 11 return DB_TABLESPACE_EXISTS;
5475 }
5476
5477 101898 return DB_SUCCESS;
5478 }
5479
5480 /** Rename a single-table tablespace.
5481 The tablespace must exist in the memory cache.
5482 @param[in] space_id Tablespace ID
5483 @param[in] old_path Old file name
5484 @param[in] new_name New tablespace name in the schema/space
5485 @param[in] new_path_in New file name, or nullptr if it is located
5486 in the normal data directory
5487 @return InnoDB error code */
5488 79857 dberr_t Fil_shard::space_rename(space_id_t space_id, const char *old_path,
5489 const char *new_name, const char *new_path_in) {
5490 fil_space_t *space;
5491 79857 ulint count = 0;
5492 79857 fil_node_t *file = nullptr;
5493 79857 bool write_ddl_log = true;
5494 79857 auto start_time = std::chrono::steady_clock::now();
5495
5496 #ifdef UNIV_DEBUG
5497 static uint32_t crash_injection_rename_tablespace_counter = 1;
5498 #endif /* UNIV_DEBUG */
5499
5500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79857 times.
79857 ut_a(space_id != TRX_SYS_SPACE);
5501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79857 times.
79857 ut_ad(strchr(new_name, '/') != nullptr);
5502
5503 for (;;) {
5504 160072 bool retry = false;
5505 160072 bool flush = false;
5506
5507 160072 ++count;
5508
5509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160072 times.
160072 if (!(count % 1000)) {
5510 ib::warn(ER_IB_MSG_295, old_path, ulong{space_id}, ulonglong{count});
5511 }
5512
5513 /* The name map and space ID map are in the same shard. */
5514
1/2
✓ Branch 0 taken 160072 times.
✗ Branch 1 not taken.
160072 mutex_acquire();
5515
5516
1/2
✓ Branch 0 taken 160072 times.
✗ Branch 1 not taken.
160072 space = get_space_by_id(space_id);
5517
5518
3/4
✓ Branch 0 taken 160072 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 160071 times.
160072 DBUG_EXECUTE_IF("fil_rename_tablespace_failure_1", space = nullptr;);
5519
5520
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 160071 times.
160072 if (space == nullptr) {
5521
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ib::error(ER_IB_MSG_296, ulong{space_id}, old_path);
5522
5523
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 mutex_release();
5524
5525 1 return DB_ERROR;
5526
5527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
160071 } else if (space->prevent_file_open) {
5528 /* Some other thread has stopped the IO. We need to
5529 wait for the other thread to complete its operation. */
5530 mutex_release();
5531
5532 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
5533 ib::warn(ER_IB_MSG_297);
5534
5535 start_time = std::chrono::steady_clock::now();
5536 }
5537
5538 std::this_thread::sleep_for(std::chrono::seconds(1));
5539
5540 continue;
5541
5542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
160071 } else if (count > 25000) {
5543 mutex_release();
5544
5545 return DB_ERROR;
5546
5547
2/4
✓ Branch 0 taken 160071 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 160071 times.
160071 } else if (space != get_space_by_name(space->name)) {
5548 ib::error(ER_IB_MSG_298, space->name);
5549
5550 mutex_release();
5551
5552 return DB_ERROR;
5553
5554 } else {
5555
1/2
✓ Branch 0 taken 160071 times.
✗ Branch 1 not taken.
160071 auto new_space = get_space_by_name(new_name);
5556
5557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
160071 if (new_space != nullptr) {
5558 if (new_space == space) {
5559 mutex_release();
5560
5561 return DB_SUCCESS;
5562 }
5563
5564 ut_a(new_space->id == space->id);
5565 }
5566 }
5567
5568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160071 times.
160071 ut_a(space->files.size() == 1);
5569
5570 #ifndef UNIV_HOTBACKUP
5571 /* Don't write DDL log during recovery when log_ddl is
5572 not initialized. */
5573
5574
3/4
✓ Branch 0 taken 79856 times.
✓ Branch 1 taken 80215 times.
✓ Branch 2 taken 79856 times.
✗ Branch 3 not taken.
160071 if (write_ddl_log && log_ddl != nullptr) {
5575 /* Write ddl log when space->prevent_file_open is true
5576 can cause deadlock:
5577 a. buffer flush thread waits for rename thread to set
5578 prevent_file_open to false;
5579 b. rename thread waits for buffer flush thread to flush
5580 a page and release page lock. The page is ready for
5581 flush in double write buffer. */
5582
5583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
79856 ut_ad(!space->prevent_file_open);
5584
5585 79856 file = &space->files.front();
5586
5587 char *new_file_name = new_path_in == nullptr
5588
2/12
✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 79856 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
159712 ? Fil_path::make_ibd_from_table_name(new_name)
5589
2/4
✓ Branch 0 taken 79856 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79856 times.
79856 : mem_strdup(new_path_in);
5590
5591 79856 char *old_file_name = file->name;
5592
5593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
79856 ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != nullptr);
5594
5595
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79856 times.
79856 ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != nullptr);
5596
5597
1/2
✓ Branch 0 taken 79856 times.
✗ Branch 1 not taken.
79856 mutex_release();
5598
5599 /* Rename ddl log is for rollback, so we exchange
5600 old file name with new file name. */
5601
1/2
✓ Branch 0 taken 79722 times.
✗ Branch 1 not taken.
79856 dberr_t err = log_ddl->write_rename_space_log(space_id, new_file_name,
5602 old_file_name);
5603 79722 ut::free(new_file_name);
5604
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 79720 times.
79722 if (err != DB_SUCCESS) {
5605 2 return err;
5606 }
5607
5608 79720 write_ddl_log = false;
5609 79720 continue;
5610 79720 }
5611 #endif /* !UNIV_HOTBACKUP */
5612
5613 /* We temporarily close the .ibd file because we do
5614 not trust that operating systems can rename an open
5615 file. For the closing we have to wait until there
5616 are no pending I/O's or flushes on the file. */
5617
5618 80215 space->prevent_file_open = true;
5619
5620 80215 file = &space->files.front();
5621
5622
4/4
✓ Branch 0 taken 80172 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 79900 times.
✓ Branch 3 taken 272 times.
80215 if (file->n_pending_ios > 0 || file->n_pending_flushes > 0 ||
5623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79900 times.
79900 file->is_being_extended) {
5624 /* There are pending I/O's or flushes or the
5625 file is currently being extended, sleep for
5626 a while and retry */
5627
5628 315 retry = true;
5629
5630 315 space->prevent_file_open = false;
5631
5632
3/4
✓ Branch 0 taken 79900 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✓ Branch 3 taken 79720 times.
79900 } else if (!file->is_flushed()) {
5633 /* Flush the space */
5634
5635 180 retry = flush = true;
5636
5637 180 space->prevent_file_open = false;
5638
5639
2/2
✓ Branch 0 taken 39883 times.
✓ Branch 1 taken 39837 times.
79720 } else if (file->is_open) {
5640
1/2
✓ Branch 0 taken 39883 times.
✗ Branch 1 not taken.
39883 close_file(file);
5641 }
5642
5643
2/2
✓ Branch 0 taken 79720 times.
✓ Branch 1 taken 495 times.
80215 if (!retry) {
5644
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79720 times.
79720 ut_ad(space->prevent_file_open);
5645 }
5646
5647
1/2
✓ Branch 0 taken 80215 times.
✗ Branch 1 not taken.
80215 mutex_release();
5648
5649
2/2
✓ Branch 0 taken 79720 times.
✓ Branch 1 taken 495 times.
80215 if (!retry) {
5650 79720 break;
5651 }
5652
5653
1/2
✓ Branch 0 taken 495 times.
✗ Branch 1 not taken.
495 std::this_thread::sleep_for(std::chrono::milliseconds(100));
5654
5655
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 315 times.
495 if (flush) {
5656
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 mutex_acquire();
5657
5658
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 space_flush(space->id);
5659
5660
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 mutex_release();
5661 }
5662 80215 }
5663
5664 #ifndef UNIV_HOTBACKUP
5665 /* Make sure we re not holding shard mutex. */
5666
2/4
✓ Branch 0 taken 79720 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79720 times.
79720 ut_ad(!mutex_owned());
5667
1/2
✓ Branch 0 taken 79720 times.
✗ Branch 1 not taken.
79720 Clone_notify notifier(Clone_notify::Type::SPACE_RENAME, space_id, false);
5668
5669
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 79718 times.
79720 if (notifier.failed()) {
5670
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_acquire();
5671 2 space->prevent_file_open = false;
5672
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_release();
5673
5674 2 return DB_ERROR;
5675 }
5676 #endif /* !UNIV_HOTBACKUP */
5677
5678 char *new_file_name;
5679
5680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79718 times.
79718 if (new_path_in == nullptr) {
5681 new_file_name = Fil_path::make_ibd_from_table_name(new_name);
5682 } else {
5683
1/2
✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
79718 new_file_name = mem_strdup(new_path_in);
5684 }
5685
5686 79718 char *old_file_name = file->name;
5687 79718 char *old_space_name = space->name;
5688
1/2
✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
79718 char *new_space_name = mem_strdup(new_name);
5689
5690 #ifndef UNIV_HOTBACKUP
5691
1/2
✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
79718 if (!recv_recovery_on) {
5692
1/2
✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
79718 mtr_t mtr;
5693
5694
1/2
✓ Branch 0 taken 79718 times.
✗ Branch 1 not taken.
79718 mtr.start();
5695
5696
1/2
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
79718 fil_name_write_rename(space_id, old_file_name, new_file_name, &mtr);
5697
5698
1/2
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
79717 mtr.commit();
5699 79717 }
5700 #endif /* !UNIV_HOTBACKUP */
5701
5702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
79717 ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != nullptr);
5703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
79717 ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != nullptr);
5704
5705
1/2
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
79717 mutex_acquire();
5706
5707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
79717 ut_ad(space->prevent_file_open);
5708
5709 /* We already checked these. */
5710
2/4
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79717 times.
79717 ut_ad(space == get_space_by_name(old_space_name));
5711
2/4
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79717 times.
79717 ut_ad(get_space_by_name(new_space_name) == nullptr);
5712
5713 bool success;
5714
5715
3/4
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 79716 times.
79717 DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2", goto skip_rename;);
5716
5717
2/6
✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79716 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
79716 DBUG_INJECT_CRASH("ddl_crash_before_rename_tablespace",
5718 crash_injection_rename_tablespace_counter++);
5719
5720 79716 file = &space->files.front();
5721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79716 times.
79716 ut_ad(!file->is_open);
5722
5723
1/2
✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
79716 success = os_file_rename(innodb_data_file_key, old_file_name, new_file_name);
5724
5725
2/4
✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79716 times.
79717 DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2", skip_rename
5726 : success = false;);
5727
5728
2/6
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79717 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
79717 DBUG_INJECT_CRASH("ddl_crash_after_rename_tablespace",
5729 crash_injection_rename_tablespace_counter++);
5730
5731
2/2
✓ Branch 0 taken 79716 times.
✓ Branch 1 taken 1 times.
79717 if (success) {
5732 79716 file->name = new_file_name;
5733
5734
1/2
✓ Branch 0 taken 79716 times.
✗ Branch 1 not taken.
79716 update_space_name_map(space, new_space_name);
5735
5736 79716 space->name = new_space_name;
5737
5738 } else {
5739 /* Because nothing was renamed, we must free the new
5740 names, not the old ones. */
5741 1 old_file_name = new_file_name;
5742 1 old_space_name = new_space_name;
5743 }
5744
5745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79717 times.
79717 ut_ad(space->prevent_file_open);
5746 79717 space->prevent_file_open = false;
5747
5748
1/2
✓ Branch 0 taken 79717 times.
✗ Branch 1 not taken.
79717 mutex_release();
5749
5750 79717 ut::free(old_file_name);
5751 79717 ut::free(old_space_name);
5752
5753
2/2
✓ Branch 0 taken 79716 times.
✓ Branch 1 taken 1 times.
79717 return success ? DB_SUCCESS : DB_ERROR;
5754 79719 }
5755
5756 /** Rename a single-table tablespace.
5757 The tablespace must exist in the memory cache.
5758 @param[in] space_id Tablespace ID
5759 @param[in] old_path Old file name
5760 @param[in] new_name New tablespace name in the schema/name format
5761 @param[in] new_path_in New file name, or nullptr if it is located in
5762 the normal data directory
5763 @return InnoDB error code */
5764 79857 dberr_t fil_rename_tablespace(space_id_t space_id, const char *old_path,
5765 const char *new_name, const char *new_path_in) {
5766 79857 auto shard = fil_system->shard_by_id(space_id);
5767
5768 79857 dberr_t err = shard->space_rename(space_id, old_path, new_name, new_path_in);
5769
5770 79722 return err;
5771 }
5772
5773 /** Rename a tablespace. Use the space_id to find the shard.
5774 @param[in] space_id tablespace ID
5775 @param[in] old_name old tablespace name
5776 @param[in] new_name new tablespace name
5777 @return DB_SUCCESS on success */
5778 78 dberr_t Fil_system::rename_tablespace_name(space_id_t space_id,
5779 const char *old_name,
5780 const char *new_name) {
5781 78 auto old_shard = fil_system->shard_by_id(space_id);
5782
5783 78 old_shard->mutex_acquire();
5784
5785 78 auto old_space = old_shard->get_space_by_id(space_id);
5786
5787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (old_space == nullptr) {
5788 old_shard->mutex_release();
5789
5790 ib::error(ER_IB_MSG_299, old_name);
5791
5792 return DB_TABLESPACE_NOT_FOUND;
5793 }
5794
5795
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 ut_ad(old_space == old_shard->get_space_by_name(old_name));
5796 78 old_shard->mutex_release();
5797
5798 78 Fil_shard *new_shard{};
5799 78 fil_space_t *new_space{};
5800
5801 78 mutex_acquire_all();
5802
5803
2/2
✓ Branch 0 taken 5304 times.
✓ Branch 1 taken 78 times.
5382 for (auto shard : m_shards) {
5804
1/2
✓ Branch 0 taken 5304 times.
✗ Branch 1 not taken.
5304 new_space = shard->get_space_by_name(new_name);
5805
5806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5304 times.
5304 if (new_space != nullptr) {
5807 new_shard = shard;
5808 break;
5809 }
5810 }
5811
5812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (new_space != nullptr) {
5813 mutex_release_all();
5814
5815 if (new_space->id != old_space->id) {
5816 ib::error(ER_IB_MSG_300, new_name);
5817
5818 return DB_TABLESPACE_EXISTS;
5819 } else {
5820 ut_a(new_shard == old_shard);
5821 }
5822
5823 return DB_SUCCESS;
5824 }
5825
5826 78 auto new_space_name = mem_strdup(new_name);
5827 78 auto old_space_name = old_space->name;
5828
5829 78 old_shard->update_space_name_map(old_space, new_space_name);
5830
5831 78 old_space->name = new_space_name;
5832
5833 78 mutex_release_all();
5834
5835 78 ut::free(old_space_name);
5836
5837 78 return DB_SUCCESS;
5838 }
5839
5840 78 dberr_t fil_rename_tablespace_by_id(space_id_t space_id, const char *old_name,
5841 const char *new_name) {
5842 78 return fil_system->rename_tablespace_name(space_id, old_name, new_name);
5843 }
5844
5845 294623 dberr_t fil_write_initial_pages(pfs_os_file_t file, const char *path,
5846 fil_type_t type [[maybe_unused]],
5847 page_no_t size, const byte *encrypt_info,
5848 space_id_t space_id, uint32_t &space_flags,
5849 bool &atomic_write, bool &punch_hole) {
5850 294623 bool success = false;
5851 294623 atomic_write = false;
5852 294623 punch_hole = false;
5853
5854
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294623 const page_size_t page_size(space_flags);
5855
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294623 const auto sz = ulonglong{size * page_size.physical()};
5856
5857 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
5858 {
5859 294623 int ret = 0;
5860 #ifdef UNIV_DEBUG
5861
3/4
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 294613 times.
294623 DBUG_EXECUTE_IF("fil_create_temp_tablespace_fail_fallocate", ret = -1;);
5862
2/2
✓ Branch 0 taken 294613 times.
✓ Branch 1 taken 10 times.
294623 if (ret == 0)
5863 #endif /* UNIV_DEBUG */
5864 {
5865
1/2
✓ Branch 0 taken 294613 times.
✗ Branch 1 not taken.
294613 ret = posix_fallocate(file.m_file, 0, sz);
5866 }
5867
5868
2/2
✓ Branch 0 taken 294613 times.
✓ Branch 1 taken 10 times.
294623 if (ret == 0) {
5869 294613 success = true;
5870
4/4
✓ Branch 0 taken 197923 times.
✓ Branch 1 taken 96690 times.
✓ Branch 2 taken 96690 times.
✓ Branch 3 taken 197923 times.
492536 if (type == FIL_TYPE_TEMPORARY ||
5871
2/4
✓ Branch 0 taken 197923 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 197923 times.
197923 fil_fusionio_enable_atomic_write(file)) {
5872 96690 atomic_write = true;
5873 }
5874 } else {
5875 /* If posix_fallocate() fails for any reason, issue only a warning
5876 and then fall back to os_file_set_size() */
5877
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 ib::warn(ER_IB_MSG_303, path, sz, ret, strerror(errno));
5878 }
5879 }
5880 #endif /* !NO_FALLOCATE && UNIV_LINUX */
5881
5882
6/6
✓ Branch 0 taken 294613 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 294580 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 197920 times.
✓ Branch 5 taken 96660 times.
294623 if (!success || (tbsp_extend_and_initialize && !atomic_write)) {
5883
1/2
✓ Branch 0 taken 197930 times.
✗ Branch 1 not taken.
197930 success = os_file_set_size(path, file, 0, sz, true);
5884
5885
1/2
✓ Branch 0 taken 197930 times.
✗ Branch 1 not taken.
197930 if (success) {
5886 /* explicit initialization is needed as same as fil_space_extend(),
5887 instead of punch_hole. */
5888 dberr_t err =
5889
2/4
✓ Branch 0 taken 197930 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197930 times.
✗ Branch 3 not taken.
197930 os_file_write_zeros(file, path, page_size.physical(), 0, sz);
5890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197930 times.
197930 if (err != DB_SUCCESS) {
5891 ib::warn(ER_IB_MSG_320) << "Error while writing " << sz << " zeroes to "
5892 << path << " starting at offset " << 0;
5893 }
5894 }
5895 }
5896
5897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294623 times.
294623 if (!success) {
5898 return DB_OUT_OF_DISK_SPACE;
5899 }
5900
5901 /* Note: We are actually punching a hole, previous contents will
5902 be lost after this call, if it succeeds. In this case the file
5903 should be full of NULs. */
5904
5905
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294623 punch_hole = os_is_sparse_file_supported(file);
5906
5907 /* Should not make large punch hole as initialization of large file,
5908 for crash-recovery safeness around disk-full. */
5909
5910 /* We have to write the space id to the file immediately and flush the
5911 file to disk. This is because in crash recovery we must be aware what
5912 tablespaces exist and what are their space id's, so that we can apply
5913 the log records to the right file. It may take quite a while until
5914 buffer pool flush algorithms write anything to the file and flush it to
5915 disk. If we would not write here anything, the file would be filled
5916 with zeros from the call of os_file_set_size(), until a buffer pool
5917 flush would write to it. */
5918
5919 /* Align the memory for file i/o if we might have O_DIRECT set */
5920 auto page = static_cast<byte *>(
5921
2/4
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 294623 times.
✗ Branch 3 not taken.
294623 ut::aligned_zalloc(2 * page_size.logical(), page_size.logical()));
5922
5923 /* Add the UNIV_PAGE_SIZE to the table flags and write them to the
5924 tablespace header. */
5925
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294622 space_flags = fsp_flags_set_page_size(space_flags, page_size);
5926
1/2
✓ Branch 0 taken 294622 times.
✗ Branch 1 not taken.
294623 fsp_header_init_fields(page, space_id, space_flags);
5927
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294622 mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
5928
5929
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294623 mach_write_to_4(page + FIL_PAGE_SRV_VERSION, DD_SPACE_CURRENT_SRV_VERSION);
5930
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294623 mach_write_to_4(page + FIL_PAGE_SPACE_VERSION,
5931 DD_SPACE_CURRENT_SPACE_VERSION);
5932
5933
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 294603 times.
294623 if (encrypt_info != nullptr) {
5934
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 auto key_offset = fsp_header_get_encryption_offset(page_size);
5935 20 memcpy(page + key_offset, encrypt_info, Encryption::INFO_SIZE);
5936 }
5937
5938
1/2
✓ Branch 0 taken 294623 times.
✗ Branch 1 not taken.
294623 IORequest request(IORequest::WRITE);
5939 294623 dberr_t err = DB_SUCCESS;
5940
5941
2/2
✓ Branch 0 taken 293376 times.
✓ Branch 1 taken 1247 times.
294623 if (!page_size.is_compressed()) {
5942 293376 buf_flush_init_for_writing(nullptr, page, nullptr, 0,
5943
2/4
✓ Branch 0 taken 293376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 293376 times.
✗ Branch 3 not taken.
293376 fsp_is_checksum_disabled(space_id),
5944 true /* skip_lsn_check */);
5945
5946
2/4
✓ Branch 0 taken 293376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 293376 times.
✗ Branch 3 not taken.
293376 err = os_file_write(request, path, file, page, 0, page_size.physical());
5947
5948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 293376 times.
293376 ut_ad(err != DB_IO_NO_PUNCH_HOLE);
5949
5950 } else {
5951 page_zip_des_t page_zip;
5952
5953
2/4
✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1247 times.
✗ Branch 3 not taken.
1247 page_zip_set_size(&page_zip, page_size.physical());
5954
1/2
✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
1247 page_zip.data = page + page_size.logical();
5955 1247 ut_d(page_zip.m_start = 0);
5956 1247 page_zip.m_end = 0;
5957 1247 page_zip.n_blobs = 0;
5958 1247 page_zip.m_nonempty = false;
5959
5960 1247 buf_flush_init_for_writing(nullptr, page, &page_zip, 0,
5961
2/4
✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1247 times.
✗ Branch 3 not taken.
1247 fsp_is_checksum_disabled(space_id),
5962 true /* skip_lsn_check */);
5963
5964
2/4
✓ Branch 0 taken 1247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1247 times.
✗ Branch 3 not taken.
1247 err = os_file_write(request, path, file, page_zip.data, 0,
5965 page_size.physical());
5966
5967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1247 times.
1247 ut_a(err != DB_IO_NO_PUNCH_HOLE);
5968
5969 1247 punch_hole = false;
5970 }
5971
5972 294623 ut::aligned_free(page);
5973 294622 return err;
5974 294622 }
5975
5976 /** Create a tablespace (an IBD or IBT) file
5977 @param[in] space_id Tablespace ID
5978 @param[in] name Tablespace name in dbname/tablename format.
5979 For general tablespaces, the 'dbname/' part
5980 may be missing.
5981 @param[in] path Path and filename of the datafile to create.
5982 @param[in] flags Tablespace flags
5983 @param[in] size Initial size of the tablespace file in pages,
5984 must be >= FIL_IBD_FILE_INITIAL_SIZE
5985 @param[in] type FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY
5986 @param[in] mode keyring encryption mode
5987 @param[in] keyring_encryption_key_id info on keyring encryption key
5988 @return DB_SUCCESS or error code */
5989 294360 static dberr_t fil_create_tablespace(
5990 space_id_t space_id, const char *name, const char *path, uint32_t flags,
5991 page_no_t size, fil_type_t type, const fil_encryption_t mode,
5992 const KeyringEncryptionKeyIdInfo &keyring_encryption_key_id) {
5993 294360 fil_space_crypt_t *crypt_data = nullptr;
5994
5995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294360 times.
294360 ut_ad(!fsp_is_system_tablespace(space_id));
5996
2/4
✓ Branch 0 taken 294360 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 294360 times.
294360 ut_a(fsp_flags_is_valid(flags));
5997
4/6
✓ Branch 0 taken 197660 times.
✓ Branch 1 taken 96700 times.
✓ Branch 2 taken 197660 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 294360 times.
294360 ut_a(type == FIL_TYPE_TEMPORARY || type == FIL_TYPE_TABLESPACE);
5998
5999 294360 bool has_shared_space = FSP_FLAGS_GET_SHARED(flags);
6000 /* Create the subdirectories in the path, if they are
6001 not there already. */
6002
2/2
✓ Branch 0 taken 196494 times.
✓ Branch 1 taken 97866 times.
294360 if (!has_shared_space) {
6003
1/2
✓ Branch 0 taken 196494 times.
✗ Branch 1 not taken.
196494 auto err = os_file_create_subdirs_if_needed(path);
6004
6005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196494 times.
196494 if (err != DB_SUCCESS) {
6006 return err; /* purecov: inspected */
6007 }
6008 }
6009
6010 294360 bool success = false;
6011
6012
6/8
✓ Branch 0 taken 410 times.
✓ Branch 1 taken 293950 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 410 times.
✓ Branch 4 taken 96700 times.
✓ Branch 5 taken 197660 times.
✓ Branch 6 taken 294360 times.
✗ Branch 7 not taken.
294360 auto file = os_file_create(
6013 type == FIL_TYPE_TEMPORARY ? innodb_temp_file_key : innodb_data_file_key,
6014 path, OS_FILE_CREATE | OS_FILE_ON_ERROR_NO_EXIT, OS_FILE_NORMAL,
6015 OS_DATA_FILE, srv_read_only_mode && (type != FIL_TYPE_TEMPORARY),
6016 &success);
6017
6018
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 294353 times.
294360 if (!success) {
6019 /* purecov: begin inspected */
6020 /* The following call will print an error message */
6021
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ulint error = os_file_get_last_error(true);
6022
6023
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ib::error(ER_IB_MSG_301, path);
6024
6025
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 switch (error) {
6026 case OS_FILE_ALREADY_EXISTS:
6027 #ifndef UNIV_HOTBACKUP
6028 ib::error(ER_IB_MSG_UNEXPECTED_FILE_EXISTS, path, path);
6029 return DB_TABLESPACE_EXISTS;
6030 #else /* !UNIV_HOTBACKUP */
6031 return DB_SUCCESS; /* Already existing file not an error here. */
6032 #endif /* !UNIV_HOTBACKUP */
6033
6034 case OS_FILE_NAME_TOO_LONG:
6035 ib::error(ER_IB_MSG_TOO_LONG_PATH, path);
6036 return DB_TOO_LONG_PATH;
6037
6038 case OS_FILE_DISK_FULL:
6039 return DB_OUT_OF_DISK_SPACE;
6040
6041 7 default:
6042 7 return DB_ERROR;
6043 }
6044 /* purecov: end */
6045 }
6046
6047 294353 bool atomic_write = false;
6048 294353 bool punch_hole = false;
6049
6050
1/2
✓ Branch 0 taken 294352 times.
✗ Branch 1 not taken.
294353 auto err = fil_write_initial_pages(file, path, type, size, nullptr, space_id,
6051 flags, atomic_write, punch_hole);
6052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294352 times.
294352 if (err != DB_SUCCESS) {
6053 ib::error(ER_IB_MSG_304, path);
6054
6055 os_file_close(file);
6056 os_file_delete(innodb_data_file_key, path);
6057
6058 return err;
6059 }
6060
6061
1/2
✓ Branch 0 taken 294352 times.
✗ Branch 1 not taken.
294352 success = os_file_flush(file);
6062
6063
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294352 times.
294352 if (!success) {
6064 ib::error(ER_IB_MSG_305, path);
6065
6066 os_file_close(file);
6067 os_file_delete(innodb_data_file_key, path);
6068 return DB_ERROR;
6069 }
6070
6071 #ifndef UNIV_HOTBACKUP
6072 /* Notifier block covers space creation and initialization. */
6073
1/2
✓ Branch 0 taken 294353 times.
✗ Branch 1 not taken.
588705 Clone_notify notifier(Clone_notify::Type::SPACE_CREATE, space_id, false);
6074
6075
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 294349 times.
294353 if (notifier.failed()) {
6076
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 os_file_close(file);
6077
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 fil_space_destroy_crypt_data(&crypt_data);
6078 4 return DB_ERROR;
6079 }
6080 #endif /* !UNIV_HOTBACKUP */
6081
6082
1/2
✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
294349 auto space = fil_space_create(name, space_id, flags, type, crypt_data, mode);
6083
6084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294349 times.
294349 if (space == nullptr) {
6085 os_file_close(file);
6086 os_file_delete(innodb_data_file_key, path);
6087
6088 return DB_ERROR;
6089 }
6090
6091
3/4
✓ Branch 0 taken 286279 times.
✓ Branch 1 taken 8070 times.
✓ Branch 2 taken 286279 times.
✗ Branch 3 not taken.
294349 DEBUG_SYNC_C("fil_ibd_created_space");
6092
6093
1/2
✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
294349 auto shard = fil_system->shard_by_id(space_id);
6094
6095 fil_node_t *file_node =
6096
1/2
✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
294349 shard->create_node(path, size, space, false, punch_hole, atomic_write);
6097
6098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294349 times.
294349 err = (file_node == nullptr) ? DB_ERROR : DB_SUCCESS;
6099
6100 #ifndef UNIV_HOTBACKUP
6101 /* Temporary tablespace creation need not be redo logged */
6102
3/4
✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197649 times.
✓ Branch 3 taken 96700 times.
294349 if (err == DB_SUCCESS && type != FIL_TYPE_TEMPORARY) {
6103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197649 times.
197649 ut_a(space->files.size() == 1);
6104 197649 const auto &file = space->files.front();
6105
6106
1/2
✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
197649 mtr_t mtr;
6107
6108
1/2
✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
197649 mtr_start(&mtr);
6109
6110
1/2
✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
197649 fil_op_write_log(MLOG_FILE_CREATE, space_id, file.name, nullptr,
6111 space->flags, &mtr);
6112
6113
1/2
✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
197649 mtr_commit(&mtr);
6114
6115
4/6
✓ Branch 0 taken 197649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 197648 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
197649 DBUG_EXECUTE_IF("fil_ibd_create_log", log_make_latest_checkpoint(););
6116 197649 }
6117
6118 #endif /* !UNIV_HOTBACKUP */
6119
6120 /* For encryption tablespace, initial encryption information. */
6121
5/6
✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1556 times.
✓ Branch 3 taken 292793 times.
✓ Branch 4 taken 1556 times.
✓ Branch 5 taken 292793 times.
588698 if (space != nullptr &&
6122 294349 (FSP_FLAGS_GET_ENCRYPTION(space->flags))) {
6123
1/2
✓ Branch 0 taken 1556 times.
✗ Branch 1 not taken.
1556 err = fil_set_encryption(
6124 space->id,
6125 Encryption::AES, nullptr,
6126 nullptr);
6127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1556 times.
1556 ut_ad(err == DB_SUCCESS);
6128 }
6129
6130 294349 space->encryption_op_in_progress = Encryption::Progress::NONE;
6131
6132
1/2
✓ Branch 0 taken 294349 times.
✗ Branch 1 not taken.
294349 os_file_close(file);
6133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294349 times.
294349 if (err != DB_SUCCESS) {
6134 os_file_delete(innodb_data_file_key, path);
6135 }
6136
6137 294349 return err;
6138 }
6139
6140 197660 dberr_t fil_ibd_create(
6141 space_id_t space_id, const char *name, const char *path, uint32_t flags,
6142 page_no_t size, const fil_encryption_t mode,
6143 const KeyringEncryptionKeyIdInfo &keyring_encryption_key_id) {
6144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197660 times.
197660 ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
6145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197660 times.
197660 ut_ad(!srv_read_only_mode);
6146 197660 return fil_create_tablespace(space_id, name, path, flags, size,
6147 FIL_TYPE_TABLESPACE, mode,
6148 197660 keyring_encryption_key_id);
6149 }
6150
6151 96700 dberr_t fil_ibt_create(space_id_t space_id, const char *name, const char *path,
6152 uint32_t flags, page_no_t size) {
6153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96700 times.
96700 ut_a(size >= FIL_IBT_FILE_INITIAL_SIZE);
6154
1/2
✓ Branch 0 taken 96700 times.
✗ Branch 1 not taken.
96700 return fil_create_tablespace(space_id, name, path, flags, size,
6155 FIL_TYPE_TEMPORARY, FIL_ENCRYPTION_DEFAULT,
6156 193400 KeyringEncryptionKeyIdInfo());
6157 }
6158
6159 #ifndef UNIV_HOTBACKUP
6160 53899 dberr_t fil_ibd_open(bool validate, fil_type_t purpose, space_id_t space_id,
6161 uint32_t flags, const char *space_name,
6162 const char *path_in, bool strict, bool old_space,
6163 Keyring_encryption_info &keyring_encryption_info) {
6164 53899 Datafile df;
6165 53899 bool is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags);
6166 53899 bool for_import = (purpose == FIL_TYPE_IMPORT);
6167
6168
3/4
✓ Branch 0 taken 53899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 53897 times.
53899 if (!fsp_flags_is_valid(flags)) {
6169 2 return DB_CORRUPTION;
6170 }
6171
6172 /* Check if the file is already open. The space can be loaded
6173 via fil_space_get_first_path() on startup. This is a problem
6174 for partitioning code. It's a convoluted call graph via the DD.
6175 On Windows this can lead to a sharing violation when we attempt
6176 to open it again. */
6177
6178
1/2
✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
53897 auto shard = fil_system->shard_by_id(space_id);
6179
6180
1/2
✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
53897 shard->mutex_acquire();
6181
6182
1/2
✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
53897 auto space = shard->get_space_by_id(space_id);
6183
6184
1/2
✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
53897 shard->mutex_release();
6185
6186
1/2
✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
53897 df.init(space_name, flags);
6187
6188
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 53747 times.
53897 if (path_in == nullptr) {
6189
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 df.make_filepath(nullptr, space_name, IBD);
6190 } else {
6191
1/2
✓ Branch 0 taken 53747 times.
✗ Branch 1 not taken.
53747 df.set_filepath(path_in);
6192 }
6193
6194 /* Attempt to open the tablespace. */
6195
3/4
✓ Branch 0 taken 53897 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53871 times.
✓ Branch 3 taken 26 times.
53897 if (df.open_read_only(strict) == DB_SUCCESS) {
6196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53871 times.
53871 ut_ad(df.is_open());
6197 } else {
6198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 ut_ad(!df.is_open());
6199 26 return DB_CANNOT_OPEN_FILE;
6200 }
6201
6202 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
6203 const bool atomic_write =
6204
5/8
✓ Branch 0 taken 445 times.
✓ Branch 1 taken 53426 times.
✓ Branch 2 taken 445 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 445 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 445 times.
53871 !dblwr::is_enabled() && fil_fusionio_enable_atomic_write(df.handle());
6205 #else
6206 const bool atomic_write = false;
6207 #endif /* !NO_FALLOCATE && UNIV_LINUX */
6208
6209 53871 Datafile::ValidateOutput validate_output;
6210
6211
6/6
✓ Branch 0 taken 34885 times.
✓ Branch 1 taken 18986 times.
✓ Branch 2 taken 374 times.
✓ Branch 3 taken 34511 times.
✓ Branch 4 taken 105 times.
✓ Branch 5 taken 53766 times.
73231 if ((validate || is_encrypted) &&
6212
1/2
✓ Branch 0 taken 19360 times.
✗ Branch 1 not taken.
19360 (validate_output = df.validate_to_dd(space_id, flags, for_import))
6213
2/2
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 19255 times.
19360 .error != DB_SUCCESS) {
6214 /* We don't reply the rename via the redo log anymore.
6215 Therefore we can get a space ID mismatch when validating
6216 the files during bootstrap. */
6217
6218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
105 if (validate_output.keyring_encryption_info.page0_has_crypt_data)
6219 keyring_encryption_info = validate_output.keyring_encryption_info;
6220
6221
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
105 if (!is_encrypted && validate_output.error != DB_WRONG_FILE_NAME) {
6222 /* The following call prints an error message.
6223 For encrypted tablespace we skip print, since it should
6224 be keyring plugin issues. */
6225
6226 os_file_get_last_error(true);
6227
6228 ib::error(ER_IB_MSG_306, space_name, TROUBLESHOOT_DATADICT_MSG);
6229 }
6230
6231 105 return validate_output.error;
6232 }
6233
6234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53766 times.
53766 if (validate_output.keyring_encryption_info.page0_has_crypt_data)
6235 keyring_encryption_info = validate_output.keyring_encryption_info;
6236
6237
6/6
✓ Branch 0 taken 18923 times.
✓ Branch 1 taken 34843 times.
✓ Branch 2 taken 18773 times.
✓ Branch 3 taken 150 times.
✓ Branch 4 taken 18232 times.
✓ Branch 5 taken 541 times.
53766 if (validate && !old_space && !for_import) {
6238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18232 times.
18232 if (df.server_version() > DD_SPACE_CURRENT_SRV_VERSION) {
6239 ib::error(ER_IB_MSG_1272, ulong{DD_SPACE_CURRENT_SRV_VERSION},
6240 ulonglong{df.server_version()});
6241 /* Server version is less than the tablespace server version.
6242 We don't support downgrade for 8.0 server, so report error */
6243 return DB_SERVER_VERSION_LOW;
6244 }
6245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18232 times.
18232 ut_ad(df.space_version() == DD_SPACE_CURRENT_SPACE_VERSION);
6246 }
6247
6248 /* We are done validating. If the tablespace is already open,
6249 return success. */
6250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53766 times.
53766 if (space != nullptr) {
6251 return DB_SUCCESS;
6252 }
6253
6254 /* We pass UNINITIALIZED flags while we try to open DD tablespace. In that
6255 case, set the flags now based on what is read from disk.*/
6256
5/8
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 53633 times.
✓ Branch 2 taken 133 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 53766 times.
53766 if (FSP_FLAGS_ARE_NOT_SET(flags) && fsp_is_dd_tablespace(space_id)) {
6257 flags = df.flags();
6258 is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags);
6259 }
6260
6261 53766 fil_space_crypt_t *crypt_data = nullptr;
6262
6263 { // Read keyring encryption data
6264 53766 bool close_df = false;
6265 54210 auto guard = create_scope_guard([&close_df, &df]() {
6266
2/2
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 53322 times.
53766 if (close_df) df.close();
6267
1/2
✓ Branch 0 taken 53766 times.
✗ Branch 1 not taken.
53766 });
6268
6269
5/6
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 53322 times.
✓ Branch 2 taken 444 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 444 times.
✓ Branch 5 taken 53322 times.
53766 if (is_encrypted && !df.is_open()) {
6270 // df.validate_to_dd closes df
6271
2/4
✓ Branch 0 taken 444 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 444 times.
444 if (df.open_read_only(strict) != DB_SUCCESS) {
6272 ut_ad(!df.is_open());
6273 return DB_CANNOT_OPEN_FILE;
6274 }
6275 444 close_df = true;
6276 }
6277
6278
2/2
✓ Branch 0 taken 34955 times.
✓ Branch 1 taken 18811 times.
53766 const byte *first_page = df.is_open() ? df.get_first_page() : nullptr;
6279 53766 crypt_data = first_page
6280
4/6
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 53322 times.
✓ Branch 2 taken 444 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 444 times.
✗ Branch 5 not taken.
53766 ? fil_space_read_crypt_data(page_size_t(flags), first_page)
6281 : nullptr;
6282
6283 53766 keyring_encryption_info.page0_has_crypt_data = crypt_data != nullptr;
6284 53766 keyring_encryption_info.is_mk_to_keyring_rotation =
6285
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 53766 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
53766 crypt_data != nullptr && crypt_data->encryption_rotation ==
6286 Encryption_rotation::MASTER_KEY_TO_KEYRING;
6287
1/2
✓ Branch 0 taken 53766 times.
✗ Branch 1 not taken.
53766 }
6288
6289
1/2
✓ Branch 0 taken 53766 times.
✗ Branch 1 not taken.
53766 space = fil_space_create(space_name, space_id, flags, purpose, crypt_data);
6290
6291
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 53764 times.
53766 if (space == nullptr) {
6292
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (crypt_data != nullptr) fil_space_destroy_crypt_data(&crypt_data);
6293 2 return DB_ERROR;
6294 }
6295
6296 /* We do not measure the size of the file, that is why
6297 we pass the 0 below */
6298
6299 const fil_node_t *file =
6300
1/2
✓ Branch 0 taken 53764 times.
✗ Branch 1 not taken.
53764 shard->create_node(df.filepath(), 0, space, false,
6301
1/2
✓ Branch 0 taken 53764 times.
✗ Branch 1 not taken.
53764 IORequest::is_punch_hole_supported(), atomic_write);
6302
6303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53764 times.
53764 if (file == nullptr) {
6304 return DB_ERROR;
6305 }
6306
6307 /* Set encryption operation in progress */
6308 53764 space->encryption_op_in_progress = df.m_encryption_op_in_progress;
6309
6310 /* It's possible during Encryption processing, space flag for encryption
6311 has been updated in ibd file but server crashed before DD flags are
6312 updated. Thus, consider ibd setting for encryption. */
6313
2/2
✓ Branch 0 taken 449 times.
✓ Branch 1 taken 53315 times.
53764 if (FSP_FLAGS_GET_ENCRYPTION(df.flags())) {
6314 449 fsp_flags_set_encryption(space->flags);
6315 } else {
6316 53315 fsp_flags_unset_encryption(space->flags);
6317 }
6318
6319 /* For encryption tablespace, initialize encryption information.*/
6320
8/8
✓ Branch 0 taken 53320 times.
✓ Branch 1 taken 444 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 53315 times.
✓ Branch 4 taken 409 times.
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 409 times.
✓ Branch 7 taken 53355 times.
54173 if ((is_encrypted || FSP_FLAGS_GET_ENCRYPTION(space->flags)) && !for_import &&
6321
1/2
✓ Branch 0 taken 409 times.
✗ Branch 1 not taken.
409 crypt_data == nullptr) {
6322 dberr_t err;
6323 409 byte *iv = df.m_encryption_iv;
6324 409 byte *key = df.m_encryption_key;
6325
6326
1/2
✓ Branch 0 taken 409 times.
✗ Branch 1 not taken.
409 err = fil_set_encryption(space->id, Encryption::AES, key, iv);
6327
6328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 409 times.
409 if (err != DB_SUCCESS) {
6329 return DB_ERROR;
6330 }
6331
6332 /* If tablespace is encrypted with default master key and server has already
6333 started, rotate it now. */
6334
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 409 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 409 times.
409 if (df.m_encryption_master_key_id == Encryption::DEFAULT_MASTER_KEY_ID &&
6335 /* There is no dependency on master thread but we are trying to check if
6336 server is in initial phase or not. */
6337 srv_master_thread_is_active()) {
6338 /* Reencrypt tablespace key */
6339 std::vector<space_id_t> sid;
6340 sid.push_back(space->id);
6341 fil_encryption_reencrypt(sid);
6342 }
6343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53355 times.
53355 } else if (crypt_data) {
6344 dberr_t err = fil_set_encryption(space->id, Encryption::KEYRING, nullptr,
6345 crypt_data->iv);
6346 if (err != DB_SUCCESS) {
6347 return (DB_ERROR);
6348 }
6349 }
6350
6351 53764 return DB_SUCCESS;
6352 53899 }
6353
6354 #else /* !UNIV_HOTBACKUP */
6355
6356 /** Allocates a file name for an old version of a single-table tablespace.
6357 The string must be freed by caller with ut::free()!
6358 @param[in] name Original file name
6359 @return own: file name */
6360 static char *meb_make_ibbackup_old_name(const char *name) {
6361 char *path;
6362 ulint len = strlen(name);
6363 static const char suffix[] = "_ibbackup_old_vers_";
6364
6365 path = static_cast<char *>(
6366 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, len + 15 + sizeof(suffix)));
6367
6368 memcpy(path, name, len);
6369 memcpy(path + len, suffix, sizeof(suffix) - 1);
6370
6371 meb_sprintf_timestamp_without_extra_chars(path + len + sizeof(suffix) - 1);
6372
6373 return path;
6374 }
6375 #endif /* UNIV_HOTBACKUP */
6376
6377 /** Looks for a pre-existing fil_space_t with the given tablespace ID
6378 and, if found, returns the name and filepath in newly allocated buffers
6379 that the caller must free.
6380 @param[in] space_id The tablespace ID to search for.
6381 @param[out] name Name of the tablespace found.
6382 @param[out] filepath The filepath of the first datafile for the
6383 tablespace.
6384 @return true if tablespace is found, false if not. */
6385 47803 bool fil_space_read_name_and_filepath(space_id_t space_id, char **name,
6386 char **filepath) {
6387 47803 bool success = false;
6388
6389 47803 *name = nullptr;
6390 47803 *filepath = nullptr;
6391
6392 47803 auto shard = fil_system->shard_by_id(space_id);
6393
6394 47803 shard->mutex_acquire();
6395
6396 47803 fil_space_t *space = shard->get_space_by_id(space_id);
6397
6398
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 47630 times.
47803 if (space != nullptr) {
6399 173 *name = mem_strdup(space->name);
6400
6401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 ut_a(space->files.size() == 1);
6402 173 *filepath = mem_strdup(space->files.front().name);
6403
6404 173 success = true;
6405 }
6406
6407 47803 shard->mutex_release();
6408
6409 47803 return success;
6410 }
6411
6412 /** Convert a file name to a tablespace name. Strip the file name
6413 prefix and suffix, leaving only databasename/tablename.
6414 @param[in] filename directory/databasename/tablename.ibd
6415 @return database/tablename string, to be freed with ut::free() */
6416 4130 char *fil_path_to_space_name(const char *filename) {
6417
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 std::string path{filename};
6418 4130 auto pos = path.find_last_of(Fil_path::SEPARATOR);
6419
6420
3/6
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4130 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4130 times.
4130 ut_a(pos != std::string::npos && !Fil_path::is_separator(path.back()));
6421
6422
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 std::string db_name = path.substr(0, pos);
6423
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 std::string space_name = path.substr(pos + 1, path.length());
6424
6425 /* If it is a path such as a/b/c.ibd, ignore everything before 'b'. */
6426 4130 pos = db_name.find_last_of(Fil_path::SEPARATOR);
6427
6428
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 if (pos != std::string::npos) {
6429
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 db_name = db_name.substr(pos + 1);
6430 }
6431
6432 char *name;
6433
6434
2/4
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4130 times.
✗ Branch 3 not taken.
4130 if (Fil_path::has_suffix(IBD, space_name)) {
6435 /* fil_space_t::name always uses '/' . */
6436
6437
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 path = db_name;
6438
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 path.push_back('/');
6439
6440 /* Strip the ".ibd" suffix. */
6441
2/4
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4130 times.
✗ Branch 3 not taken.
4130 path.append(space_name.substr(0, space_name.length() - 4));
6442
6443
1/2
✓ Branch 0 taken 4130 times.
✗ Branch 1 not taken.
4130 name = mem_strdupl(path.c_str(), path.length());
6444
6445 } else {
6446 /* Must have an "undo" prefix. */
6447 ut_ad(space_name.find("undo") == 0);
6448
6449 name = mem_strdupl(space_name.c_str(), space_name.length());
6450 }
6451
6452 4130 return name;
6453 4130 }
6454
6455 /** Open an ibd tablespace and add it to the InnoDB data structures.
6456 This is similar to fil_ibd_open() except that it is used while processing
6457 the redo and DDL log, so the data dictionary is not available and very little
6458 validation is done. The tablespace name is extracted from the
6459 dbname/tablename.ibd portion of the filename, which assumes that the file
6460 is a file-per-table tablespace. Any name will do for now. General
6461 tablespace names will be read from the dictionary after it has been
6462 recovered. The tablespace flags are read at this time from the first page
6463 of the file in validate_for_recovery().
6464 @param[in] space_id tablespace ID
6465 @param[in] path path/to/databasename/tablename.ibd
6466 @param[out] space the tablespace, or nullptr on error
6467 @return status of the operation */
6468 16121 fil_load_status Fil_shard::ibd_open_for_recovery(space_id_t space_id,
6469 const std::string &path,
6470 fil_space_t *&space) {
6471 /* If the a space is already in the file system cache with this
6472 space ID, then there is nothing to do. */
6473
6474
1/2
✓ Branch 0 taken 16121 times.
✗ Branch 1 not taken.
16121 mutex_acquire();
6475
6476
1/2
✓ Branch 0 taken 16121 times.
✗ Branch 1 not taken.
16121 space = get_space_by_id(space_id);
6477
6478
1/2
✓ Branch 0 taken 16121 times.
✗ Branch 1 not taken.
16121 mutex_release();
6479
6480 16121 const char *filename = path.c_str();
6481
6482
2/2
✓ Branch 0 taken 6698 times.
✓ Branch 1 taken 9423 times.
16121 if (space != nullptr) {
6483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6698 times.
6698 ut_a(space->files.size() == 1);
6484
6485 6698 const auto &file = space->files.front();
6486
6487 /* Compare the real paths. */
6488
4/8
✓ Branch 0 taken 6698 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6698 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6698 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6698 times.
✗ Branch 7 not taken.
6698 if (Fil_path::is_same_as(filename, file.name)) {
6489 6698 return FIL_LOAD_OK;
6490 }
6491
6492 #ifdef UNIV_HOTBACKUP
6493 ib::trace_2() << "Ignoring data file '" << filename << "' with space ID "
6494 << space->id << ". Another data file called '" << file.name
6495 << "' exists with the same space ID";
6496 #else /* UNIV_HOTBACKUP */
6497 ib::info(ER_IB_MSG_307, filename, ulong{space->id}, file.name);
6498 #endif /* UNIV_HOTBACKUP */
6499
6500 space = nullptr;
6501
6502 return FIL_LOAD_ID_CHANGED;
6503 }
6504
6505 9423 Datafile df;
6506
6507
1/2
✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
9423 df.set_filepath(filename);
6508
6509
2/4
✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9423 times.
9423 if (df.open_read_only(false) != DB_SUCCESS) {
6510 return FIL_LOAD_NOT_FOUND;
6511 }
6512
6513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9423 times.
9423 ut_ad(df.is_open());
6514
6515 /* Get and test the file size. */
6516
2/4
✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9423 times.
✗ Branch 3 not taken.
9423 os_offset_t size = os_file_get_size(df.handle());
6517
6518 /* Read and validate the first page of the tablespace. Assign a tablespace
6519 name based on the tablespace type. This will close the file, but will leave
6520 the flags and names to be queried. */
6521
1/2
✓ Branch 0 taken 9423 times.
✗ Branch 1 not taken.
9423 dberr_t err = df.validate_for_recovery(space_id).error;
6522
6523
4/8
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9419 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9423 times.
9423 ut_a(err == DB_SUCCESS || err == DB_INVALID_ENCRYPTION_META ||
6524 err == DB_CORRUPTION);
6525
6526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9423 times.
9423 if (err == DB_CORRUPTION) {
6527 return FIL_LOAD_DBWLR_CORRUPTION;
6528 }
6529
6530
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9419 times.
9423 if (err == DB_INVALID_ENCRYPTION_META) {
6531
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 bool success = fil_system->erase_path(space_id);
6532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 ut_a(success);
6533 4 return FIL_LOAD_NOT_FOUND;
6534 }
6535
6536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 ut_a(df.space_id() == space_id);
6537
6538 /* Every .ibd file is created >= 4 pages in size.
6539 Smaller files cannot be OK. */
6540 os_offset_t minimum_size;
6541
6542 /* Every .ibd file is created >= FIL_IBD_FILE_INITIAL_SIZE
6543 pages in size. Smaller files cannot be OK. */
6544 {
6545
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 const page_size_t page_size(df.flags());
6546
6547
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 minimum_size = FIL_IBD_FILE_INITIAL_SIZE * page_size.physical();
6548 }
6549
6550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 if (size == static_cast<os_offset_t>(-1)) {
6551 /* The following call prints an error message */
6552 os_file_get_last_error(true);
6553
6554 ib::error(ER_IB_MSG_308) << "Could not measure the size of"
6555 " single-table tablespace file '"
6556 << df.filepath() << "'";
6557
6558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 } else if (size < minimum_size) {
6559 #ifndef UNIV_HOTBACKUP
6560 ib::error(ER_IB_MSG_309)
6561 << "The size of tablespace file '" << df.filepath() << "' is only "
6562 << size << ", should be at least " << minimum_size << "!";
6563 #else
6564 /* In MEB, we work around this error. */
6565 df.set_space_id(SPACE_UNKNOWN);
6566 df.set_flags(0);
6567 #endif /* !UNIV_HOTBACKUP */
6568 }
6569
6570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 ut_ad(space == nullptr);
6571
6572 #ifdef UNIV_HOTBACKUP
6573 if (df.space_id() == SPACE_UNKNOWN || df.space_id() == 0) {
6574 char *new_path;
6575
6576 ib::info(ER_IB_MSG_310)
6577 << "Renaming tablespace file '" << df.filepath() << "' with space ID "
6578 << df.space_id() << " to " << df.name()
6579 << "_ibbackup_old_vers_<timestamp>"
6580 " because its size "
6581 << df.size()
6582 << " is too small"
6583 " (< 4 pages 16 kB each), or the space id in the"
6584 " file header is not sensible. This can happen in"
6585 " an mysqlbackup run, and is not dangerous.";
6586 df.close();
6587
6588 new_path = meb_make_ibbackup_old_name(df.filepath());
6589
6590 bool success =
6591 os_file_rename(innodb_data_file_key, df.filepath(), new_path);
6592
6593 ut_a(success);
6594
6595 ut::free(new_path);
6596
6597 return FIL_LOAD_ID_CHANGED;
6598 }
6599
6600 /* A backup may contain the same space several times, if the space got
6601 renamed at a sensitive time. Since it is enough to have one version of
6602 the space, we rename the file if a space with the same space id
6603 already exists in the tablespace memory cache. We rather rename the
6604 file than delete it, because if there is a bug, we do not want to
6605 destroy valuable data. */
6606
6607 mutex_acquire();
6608
6609 space = get_space_by_id(space_id);
6610
6611 mutex_release();
6612
6613 if (space != nullptr) {
6614 ib::info(ER_IB_MSG_311)
6615 << "Renaming data file '" << df.filepath() << "' with space ID "
6616 << space_id << " to " << df.name()
6617 << "_ibbackup_old_vers_<timestamp> because space " << space->name
6618 << " with the same id was scanned"
6619 " earlier. This can happen if you have renamed tables"
6620 " during an mysqlbackup run.";
6621
6622 df.close();
6623
6624 char *new_path = meb_make_ibbackup_old_name(df.filepath());
6625
6626 bool success =
6627 os_file_rename(innodb_data_file_key, df.filepath(), new_path);
6628
6629 ut_a(success);
6630
6631 ut::free(new_path);
6632 return FIL_LOAD_OK;
6633 }
6634 #endif /* UNIV_HOTBACKUP */
6635
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 std::string tablespace_name(df.name());
6636
6637 /* During the apply-log operation, MEB already has translated the
6638 file name, so file name to space name conversion is not required. */
6639 #ifndef UNIV_HOTBACKUP
6640
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 dict_name::convert_to_space(tablespace_name);
6641 #endif /* !UNIV_HOTBACKUP */
6642
6643 9419 const byte *first_page = df.get_first_page();
6644 fil_space_crypt_t *crypt_data =
6645 first_page
6646
3/6
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9419 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9419 times.
✗ Branch 5 not taken.
9419 ? fil_space_read_crypt_data(page_size_t(df.flags()), first_page)
6647 9419 : nullptr;
6648
6649
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 fil_system->mutex_acquire_all();
6650
6651
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 space = space_create(tablespace_name.c_str(), space_id, df.flags(),
6652 FIL_TYPE_TABLESPACE, crypt_data);
6653
6654
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 fil_system->mutex_release_all();
6655
6656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 if (space == nullptr) {
6657 return FIL_LOAD_INVALID;
6658 }
6659
6660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 ut_ad(space->id == df.space_id());
6661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 ut_ad(space->id == space_id);
6662
6663 /* We do not use the size information we have about the file, because
6664 the rounding formula for extents and pages is somewhat complex; we
6665 let create_node() do that task. */
6666
6667 const fil_node_t *file;
6668
6669
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 file = create_node(df.filepath(), 0, space, false, true, false);
6670
6671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9419 times.
9419 ut_a(file != nullptr);
6672
6673 /* For encryption tablespace, initial encryption information. */
6674
4/4
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 9207 times.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 9221 times.
9631 if (FSP_FLAGS_GET_ENCRYPTION(space->flags) &&
6675
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 14 times.
212 df.m_encryption_key != nullptr) {
6676
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 dberr_t err = fil_set_encryption(space->id, Encryption::AES,
6677 df.m_encryption_key, df.m_encryption_iv);
6678
6679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (err != DB_SUCCESS) {
6680 ib::error(ER_IB_MSG_312, space->name);
6681 }
6682 }
6683
6684 /* Set encryption operation in progress */
6685 9419 space->encryption_op_in_progress = df.m_encryption_op_in_progress;
6686
1/2
✓ Branch 0 taken 9419 times.
✗ Branch 1 not taken.
9419 space->m_header_page_flush_lsn = df.get_flush_lsn();
6687
6688 9419 return FIL_LOAD_OK;
6689 9423 }
6690
6691 /** Open an ibd tablespace and add it to the InnoDB data structures.
6692 This is similar to fil_ibd_open() except that it is used while processing
6693 the redo log, so the data dictionary is not available and very little
6694 validation is done. The tablespace name is extracted from the
6695 dbname/tablename.ibd portion of the filename, which assumes that the file
6696 is a file-per-table tablespace. Any name will do for now. General
6697 tablespace names will be read from the dictionary after it has been
6698 recovered. The tablespace flags are read at this time from the first page
6699 of the file in validate_for_recovery().
6700 @param[in] space_id tablespace ID
6701 @param[in] path path/to/databasename/tablename.ibd
6702 @param[out] space the tablespace, or nullptr on error
6703 @return status of the operation */
6704 16131 fil_load_status Fil_system::ibd_open_for_recovery(space_id_t space_id,
6705 const std::string &path,
6706 fil_space_t *&space) {
6707 /* System tablespace open should never come here. It should be
6708 opened explicitly using the config path. */
6709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16131 times.
16131 ut_a(space_id != TRX_SYS_SPACE);
6710
6711 #ifndef UNIV_HOTBACKUP
6712 /* Do not attempt to open or load for recovery any undo tablespace that
6713 is currently being truncated. */
6714
4/4
✓ Branch 0 taken 3697 times.
✓ Branch 1 taken 12434 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16121 times.
19828 if (fsp_is_undo_tablespace(space_id) &&
6715
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3687 times.
3697 undo::is_active_truncate_log_present(undo::id2num(space_id))) {
6716 10 return FIL_LOAD_NOT_FOUND;
6717 }
6718 #endif /* !UNIV_HOTBACKUP */
6719
6720 16121 auto shard = shard_by_id(space_id);
6721
6722 16121 return shard->ibd_open_for_recovery(space_id, path, space);
6723 }
6724
6725 #ifndef UNIV_HOTBACKUP
6726
6727 /** Report that a tablespace for a table was not found.
6728 @param[in] name Table name
6729 @param[in] space_id Table's space ID */
6730 static void fil_report_missing_tablespace(const char *name,
6731 space_id_t space_id) {
6732 ib::error(ER_IB_MSG_313)
6733 << "Table " << name << " in the InnoDB data dictionary has tablespace id "
6734 << space_id << ", but a tablespace with that id or name does not exist."
6735 << " Have you deleted or moved .ibd files?";
6736 }
6737
6738 842077 bool Fil_shard::adjust_space_name(fil_space_t *space,
6739 const char *dd_space_name) {
6740
2/2
✓ Branch 0 taken 841091 times.
✓ Branch 1 taken 986 times.
842077 if (!strcmp(space->name, dd_space_name)) {
6741 841091 return true;
6742 }
6743
6744 bool replace_general =
6745
2/2
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 829 times.
1143 FSP_FLAGS_GET_SHARED(space->flags) &&
6746
1/2
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
157 0 == strncmp(space->name, general_space_name, strlen(general_space_name));
6747 bool replace_undo =
6748
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 723 times.
1249 fsp_is_undo_tablespace(space->id) &&
6749
1/2
✓ Branch 0 taken 263 times.
✗ Branch 1 not taken.
263 0 == strncmp(space->name, undo_space_name, strlen(undo_space_name));
6750
6751 /* Update the auto-generated fil_space_t::name */
6752
4/4
✓ Branch 0 taken 829 times.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 566 times.
986 if (replace_general || replace_undo) {
6753 420 char *old_space_name = space->name;
6754 420 char *new_space_name = mem_strdup(dd_space_name);
6755
6756 420 update_space_name_map(space, new_space_name);
6757
6758 420 space->name = new_space_name;
6759
6760 420 ut::free(old_space_name);
6761 }
6762
6763 /* Update the undo::Tablespace::name. Since the fil_shard mutex is held by
6764 the caller, it would be a sync order violation to get undo::spaces->s_lock.
6765 It is OK to skip this s_lock since this occurs during boot_tablespaces()
6766 which is still single threaded. */
6767
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 723 times.
986 if (replace_undo) {
6768 263 space_id_t space_num = undo::id2num(space->id);
6769 263 undo::Tablespace *undo_space = undo::spaces->find(space_num);
6770 263 undo_space->set_space_name(dd_space_name);
6771 }
6772
6773
4/4
✓ Branch 0 taken 829 times.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 566 times.
986 return (replace_general || replace_undo);
6774 }
6775
6776 1074228 bool Fil_shard::space_check_exists(space_id_t space_id, const char *name,
6777 bool print_err, bool adjust_space) {
6778 1074228 fil_space_t *fnamespace = nullptr;
6779
6780 1074228 mutex_acquire();
6781
6782 /* Look if there is a space with the same id */
6783 1074228 fil_space_t *space = get_space_by_id(space_id);
6784
6785 /* name is nullptr when replaying a DELETE ddl log. */
6786
2/2
✓ Branch 0 taken 186214 times.
✓ Branch 1 taken 888014 times.
1074228 if (name == nullptr) {
6787 186214 mutex_release();
6788 186214 return (space != nullptr);
6789 }
6790
6791
2/2
✓ Branch 0 taken 842077 times.
✓ Branch 1 taken 45937 times.
888014 if (space != nullptr) {
6792 /* No need to check a general tablespace name if the DD
6793 is not yet available. */
6794
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 842077 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 842077 times.
842077 if (!srv_sys_tablespaces_open && FSP_FLAGS_GET_SHARED(space->flags)) {
6795 mutex_release();
6796 return true;
6797 }
6798
6799 /* Sometimes the name has been auto-generated when the
6800 datafile is discovered and needs to be adjusted to that
6801 of the DD. This happens for general and undo tablespaces. */
6802
4/6
✓ Branch 0 taken 842077 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 842077 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 841511 times.
✓ Branch 5 taken 566 times.
1684154 if (srv_sys_tablespaces_open && adjust_space &&
6803
2/2
✓ Branch 0 taken 841511 times.
✓ Branch 1 taken 566 times.
842077 adjust_space_name(space, name)) {
6804 841511 mutex_release();
6805 841511 return true;
6806 }
6807
6808 /* If this space has the expected name, use it. */
6809 566 fnamespace = get_space_by_name(name);
6810
6811
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 566 times.
566 if (space == fnamespace) {
6812 /* Found */
6813 mutex_release();
6814 return true;
6815 }
6816 }
6817
6818 /* Info from "fnamespace" comes from the ibd file itself, it can
6819 be different from data obtained from System tables since file
6820 operations are not transactional. If adjust_space is set, and the
6821 mismatching space are between a user table and its temp table, we
6822 shall adjust the ibd file name according to system table info */
6823
2/2
✓ Branch 0 taken 566 times.
✓ Branch 1 taken 45874 times.
46440 if (adjust_space && space != nullptr &&
6824
6/6
✓ Branch 0 taken 46440 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 347 times.
✓ Branch 3 taken 219 times.
✓ Branch 4 taken 347 times.
✓ Branch 5 taken 46156 times.
93290 row_is_mysql_tmp_table_name(space->name) &&
6825
1/2
✓ Branch 0 taken 347 times.
✗ Branch 1 not taken.
347 !row_is_mysql_tmp_table_name(name)) {
6826 /* Atomic DDL's "ddl_log" will adjust the tablespace name. */
6827 347 mutex_release();
6828
6829 347 return true;
6830
6831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46156 times.
46156 } else if (!print_err) {
6832 ;
6833
6834 } else if (space == nullptr) {
6835 if (fnamespace == nullptr) {
6836 if (print_err) {
6837 fil_report_missing_tablespace(name, space_id);
6838 }
6839
6840 } else {
6841 ib::error(ER_IB_MSG_314)
6842 << "Table " << name << " in InnoDB data dictionary has tablespace id "
6843 << space_id << ", but a tablespace with that id does not exist."
6844 << " But there is a tablespace of name " << fnamespace->name
6845 << " and id " << fnamespace->id
6846 << ". Have you deleted or moved .ibd files?";
6847 }
6848
6849 ib::warn(ER_IB_MSG_315) << TROUBLESHOOT_DATADICT_MSG;
6850
6851 } else if (0 != strcmp(space->name, name)) {
6852 ib::error(ER_IB_MSG_316)
6853 << "Table " << name << " in InnoDB data dictionary"
6854 << " has tablespace id " << space_id
6855 << ", but the tablespace with that id has name " << space->name
6856 << ". Have you deleted or moved .ibd files?";
6857
6858 if (fnamespace != nullptr) {
6859 ib::error(ER_IB_MSG_317)
6860 << "There is a tablespace with the name " << fnamespace->name
6861 << ", but its id is " << fnamespace->id << ".";
6862 }
6863
6864 ib::warn(ER_IB_MSG_318) << TROUBLESHOOT_DATADICT_MSG;
6865 }
6866
6867 46156 mutex_release();
6868
6869 46156 return false;
6870 }
6871
6872 1074228 bool fil_space_exists_in_mem(space_id_t space_id, const char *name,
6873 bool print_err, bool adjust_space) {
6874 1074228 auto shard = fil_system->shard_by_id(space_id);
6875
6876 1074228 return shard->space_check_exists(space_id, name, print_err, adjust_space);
6877 }
6878 #endif /* !UNIV_HOTBACKUP */
6879
6880 /** Returns the space ID based on the tablespace name.
6881 The tablespace must be found in the tablespace memory cache.
6882 This call is made from external to this module, so the mutex is not owned.
6883 @param[in] name Tablespace name
6884 @return space ID if tablespace found, SPACE_UNKNOWN if space not. */
6885 154433 space_id_t fil_space_get_id_by_name(const char *name) {
6886 154433 auto space = fil_system->get_space_by_name(name);
6887
6888
2/2
✓ Branch 0 taken 153117 times.
✓ Branch 1 taken 1316 times.
154433 return (space == nullptr) ? SPACE_UNKNOWN : space->id;
6889 }
6890
6891 /** Fill the pages with NULs
6892 @param[in] file Tablespace file
6893 @param[in] page_size physical page size
6894 @param[in] start Offset from the start of the file in bytes
6895 @param[in] len Length in bytes
6896 @return DB_SUCCESS or error code */
6897 183568 static dberr_t fil_write_zeros(const fil_node_t *file, ulint page_size,
6898 os_offset_t start, os_offset_t len) {
6899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183568 times.
183568 ut_a(len > 0);
6900
6901 /* Extend at most 1M at a time */
6902 183568 os_offset_t n_bytes = std::min(static_cast<os_offset_t>(1024 * 1024), len);
6903
6904 183568 byte *buf = reinterpret_cast<byte *>(ut::aligned_zalloc(n_bytes, page_size));
6905
6906 183568 os_offset_t offset = start;
6907 183568 dberr_t err = DB_SUCCESS;
6908 183568 const os_offset_t end = start + len;
6909
1/2
✓ Branch 0 taken 183568 times.
✗ Branch 1 not taken.
183568 IORequest request(IORequest::WRITE);
6910
6911
2/2
✓ Branch 0 taken 192794 times.
✓ Branch 1 taken 183568 times.
376362 while (offset < end) {
6912 err =
6913
1/2
✓ Branch 0 taken 192794 times.
✗ Branch 1 not taken.
192794 os_file_write(request, file->name, file->handle, buf, offset, n_bytes);
6914
6915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 192794 times.
192794 if (err != DB_SUCCESS) {
6916 break;
6917 }
6918
6919 192794 offset += n_bytes;
6920
6921 192794 n_bytes = std::min(n_bytes, end - offset);
6922
6923
2/6
✓ Branch 0 taken 192794 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 192794 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
192794 DBUG_EXECUTE_IF("ib_crash_during_tablespace_extension", DBUG_SUICIDE(););
6924 }
6925
6926 183568 ut::aligned_free(buf);
6927
6928 183568 return err;
6929 183568 }
6930
6931 /** Try to extend a tablespace if it is smaller than the specified size.
6932 @param[in,out] space tablespace
6933 @param[in] size desired size in pages
6934 @return whether the tablespace is at least as big as requested */
6935 273924 bool Fil_shard::space_extend(fil_space_t *space, page_no_t size) {
6936 /* In read-only mode we allow write to shared temporary tablespace
6937 as intrinsic table created by Optimizer reside in this tablespace. */
6938
5/8
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 273885 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 273924 times.
273924 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(space->id));
6939
6940 #ifndef UNIV_HOTBACKUP
6941
2/6
✓ Branch 0 taken 273924 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273924 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
273924 DBUG_EXECUTE_IF("fil_space_print_xdes_pages",
6942 space->print_xdes_pages("xdes_pages.log"););
6943 #endif /* !UNIV_HOTBACKUP */
6944
6945 fil_node_t *file;
6946 273924 bool success = true;
6947
6948 #ifdef UNIV_HOTBACKUP
6949 page_no_t prev_size = 0;
6950 #endif /* UNIV_HOTBACKUP */
6951
6952 for (;;) {
6953
1/2
✓ Branch 0 taken 273924 times.
✗ Branch 1 not taken.
273924 mutex_acquire();
6954
1/2
✓ Branch 0 taken 273924 times.
✗ Branch 1 not taken.
273924 space = get_space_by_id(space->id);
6955
6956 /* Note:If the file is being opened for the first time then
6957 we don't have the file physical size. There is no guarantee
6958 that the file has been opened at this stage. */
6959
6960
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 273909 times.
273924 if (size < space->size) {
6961 /* Space already big enough */
6962
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 mutex_release();
6963
6964 15 return true;
6965 }
6966
6967 273909 file = &space->files.back();
6968
6969
1/2
✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
273909 if (!file->is_being_extended) {
6970 /* Mark this file as undergoing extension. This flag
6971 is used to synchronize threads to execute space extension in order. */
6972
6973 273909 file->is_being_extended = true;
6974
6975 273909 break;
6976 }
6977
6978 /* Another thread is currently using the file. Wait
6979 for it to finish. It'd have been better to use an event
6980 driven mechanism but the entire module is peppered with
6981 polling code. */
6982
6983 mutex_release();
6984
6985 if (!tbsp_extend_and_initialize) {
6986 std::this_thread::sleep_for(std::chrono::microseconds(20));
6987 } else {
6988 std::this_thread::sleep_for(std::chrono::milliseconds(100));
6989 }
6990 }
6991
6992
2/4
✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273909 times.
273909 if (!prepare_file_for_io(file)) {
6993 /* The tablespace data file, such as .ibd file, is missing */
6994 ut_a(file->is_being_extended);
6995 file->is_being_extended = false;
6996
6997 mutex_release();
6998
6999 return false;
7000 }
7001
7002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273909 times.
273909 ut_a(file->is_open);
7003
7004
1/2
✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
273909 const page_size_t page_size(space->flags);
7005
1/2
✓ Branch 0 taken 273909 times.
✗ Branch 1 not taken.
273909 const size_t phy_page_size = page_size.physical();
7006
7007 #ifdef UNIV_HOTBACKUP
7008 prev_size = space->size;
7009
7010 ib::trace_1() << "Extending space id : " << space->id
7011 << ", space name : " << space->name
7012 << ", space size : " << space->size
7013 << " pages, page size : " << phy_page_size
7014 << ", to size : " << size;
7015 #endif /* UNIV_HOTBACKUP */
7016
7017
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 273908 times.
273909 if (size <= space->size) {
7018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 ut_a(file->is_being_extended);
7019 1 file->is_being_extended = false;
7020
7021
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 complete_io(file, IORequestRead);
7022
7023
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 mutex_release();
7024
7025 1 return true;
7026 }
7027
7028 /* At this point it is safe to release the shard mutex. No
7029 other thread can rename, delete or close the file because
7030 we have set the file->in_use flag. */
7031
7032
1/2
✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
273908 mutex_release();
7033
7034 page_no_t pages_added;
7035
1/2
✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
273908 os_offset_t node_start = os_file_get_size(file->handle);
7036
7037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273908 times.
273908 ut_a(node_start != (os_offset_t)-1);
7038
7039 /* File first page number */
7040 273908 page_no_t node_first_page = space->size - file->size;
7041
7042 /* Number of physical pages in the file */
7043 273908 page_no_t n_node_physical_pages =
7044 273908 static_cast<page_no_t>(node_start / phy_page_size);
7045
7046 /* Number of pages to extend in the file */
7047 page_no_t n_node_extend;
7048
7049 273908 n_node_extend = size - (node_first_page + file->size);
7050
7051 /* If we already have enough physical pages to satisfy the
7052 extend request on the file then ignore it */
7053
1/2
✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
273908 if (file->size + n_node_extend > n_node_physical_pages) {
7054
4/6
✓ Branch 0 taken 273908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 273907 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
273908 DBUG_EXECUTE_IF("ib_crash_during_tablespace_extension", DBUG_SUICIDE(););
7055
7056 os_offset_t len;
7057 273907 dberr_t err = DB_SUCCESS;
7058
7059 273907 len = ((file->size + n_node_extend) * phy_page_size) - node_start;
7060
7061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273907 times.
273907 ut_ad(len > 0);
7062
7063 #if !defined(UNIV_HOTBACKUP) && defined(UNIV_LINUX)
7064 /* Do not write redo log record for temporary tablespace
7065 and the system tablespace as they don't need to be recreated.
7066 Temporary tablespaces are reinitialized during startup and
7067 hence need not be recovered during recovery. The system
7068 tablespace is neither recreated nor resized and hence we do
7069 not need to redo log any operations on it. */
7070
5/6
✓ Branch 0 taken 273907 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 183403 times.
✓ Branch 3 taken 90504 times.
✓ Branch 4 taken 183399 times.
✓ Branch 5 taken 90508 times.
457310 if (!recv_recovery_is_on() && space->purpose != FIL_TYPE_TEMPORARY &&
7071
2/2
✓ Branch 0 taken 183399 times.
✓ Branch 1 taken 4 times.
183403 space->id != TRX_SYS_SPACE) {
7072 /* Write the redo log record for extending the space */
7073
1/2
✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
183399 mtr_t mtr;
7074
1/2
✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
183399 mtr_start(&mtr);
7075
7076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183399 times.
183399 ut_ad(node_start > 0);
7077
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183399 times.
183399 ut_ad(len > 0);
7078
7079 /* The posix_fallocate() reserves the desired space and updates
7080 the file metadata in the filesystem. On successful execution, any
7081 subsequent attempt to access this newly allocated space will see
7082 it as initialized because of the updated filesystem metadata.
7083
7084 However, the posix_fallocate() call used to allocate space seems
7085 to have an atomicity issue where it can fail after reserving the
7086 space, but before updating the file metadata in the filesystem.
7087
7088 Offset is required to be written in the redo log record to find
7089 out the position in the file where it was extended during space
7090 extend operation. The offset value written in the redo log can
7091 be directly used to find the starting point for initializing
7092 the file during recovery. In case posix_fallocate() crashes as
7093 described above, it will be difficult to find out the old size
7094 of the file and hence it will be difficult to find out the exact
7095 region which needs to be initialized by writing 0's. */
7096
7097
1/2
✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
183399 fil_op_write_space_extend(space->id, node_start, len, &mtr);
7098
7099
1/2
✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
183399 mtr_commit(&mtr);
7100
7101
5/8
✓ Branch 0 taken 183399 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 183397 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
183399 DBUG_INJECT_CRASH_WITH_LOG_FLUSH("ib_crash_after_writing_redo_extend", 1);
7102
7103 /* NOTE: Though against for the Write-Ahead-Log principal,
7104 log_write_up_to() is not needed here, because no file shrinks and
7105 duplicate extending is allowed. And log_write_up_to() here helps
7106 nothing for fallocate() inconsistency. */
7107 183397 }
7108 #endif /* !UNIV_HOTBACKUP && UNIV_LINUX */
7109
7110 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
7111 /* This is required by FusionIO HW/Firmware */
7112
7113
1/2
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
273905 int ret = posix_fallocate(file->handle.m_file, node_start, len);
7114
7115
3/4
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 273901 times.
273905 DBUG_EXECUTE_IF("ib_posix_fallocate_fail_eintr", ret = EINTR;);
7116
7117
2/4
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273905 times.
273905 DBUG_EXECUTE_IF("ib_posix_fallocate_fail_einval", ret = EINVAL;);
7118
7119
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 273901 times.
273905 if (ret != 0) {
7120 /* We already pass the valid offset and len in, if EINVAL
7121 is returned, it could only mean that the file system doesn't
7122 support fallocate(), currently one known case is ext3 with O_DIRECT.
7123
7124 Also because above call could be interrupted, in this case,
7125 simply go to plan B by writing zeroes.
7126
7127 Both error messages for above two scenarios are skipped in case
7128 of flooding error messages, because they can be ignored by users. */
7129
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 if (ret != EINTR && ret != EINVAL) {
7130 ib::error(ER_IB_MSG_319)
7131 << "posix_fallocate(): Failed to preallocate"
7132 " data for file "
7133 << file->name << ", desired size " << len
7134 << " bytes."
7135 " Operating system error number "
7136 << ret
7137 << ". Check"
7138 " that the disk is not full or a disk quota"
7139 " exceeded. Make sure the file system supports"
7140 " this function. Refer to your operating system"
7141 " documentation for operating system error code"
7142 " information.";
7143 }
7144
7145 4 err = DB_IO_ERROR;
7146 }
7147 #endif /* NO_FALLOCATE || !UNIV_LINUX */
7148
7149
6/6
✓ Branch 0 taken 273875 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 90496 times.
✓ Branch 3 taken 183379 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 90522 times.
273905 if ((tbsp_extend_and_initialize && !file->atomic_write) ||
7150 err == DB_IO_ERROR) {
7151
1/2
✓ Branch 0 taken 183383 times.
✗ Branch 1 not taken.
183383 err = fil_write_zeros(file, phy_page_size, node_start, len);
7152
7153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183383 times.
183383 if (err != DB_SUCCESS) {
7154 ib::warn(ER_IB_MSG_320)
7155 << "Error while writing " << len << " zeroes to " << file->name
7156 << " starting at offset " << node_start;
7157 }
7158 }
7159
7160 /* Check how many pages actually added */
7161
1/2
✓ Branch 0 taken 273904 times.
✗ Branch 1 not taken.
273905 os_offset_t end = os_file_get_size(file->handle);
7162
3/6
✓ Branch 0 taken 273904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 273905 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 273904 times.
273904 ut_a(end != static_cast<os_offset_t>(-1) && end >= node_start);
7163
7164 273904 success = (end == node_start + len);
7165 273904 os_has_said_disk_full = !success;
7166
7167 273904 pages_added = static_cast<page_no_t>(end / phy_page_size);
7168
7169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273905 times.
273904 ut_a(pages_added >= file->size);
7170 273905 pages_added -= file->size;
7171
7172 } else {
7173 success = true;
7174 pages_added = n_node_extend;
7175 os_has_said_disk_full = false;
7176 }
7177
7178
1/2
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
273905 mutex_acquire();
7179
7180 273905 file->size += pages_added;
7181 273905 space->size += pages_added;
7182
7183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273905 times.
273905 ut_a(file->is_being_extended);
7184 273905 file->is_being_extended = false;
7185
7186
2/4
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 273905 times.
✗ Branch 3 not taken.
273905 complete_io(file, IORequestWrite);
7187
7188 #ifndef UNIV_HOTBACKUP
7189 /* Keep the last data file size info up to date, rounded to
7190 full megabytes */
7191 273905 page_no_t pages_per_mb =
7192 273905 static_cast<page_no_t>((1024 * 1024) / phy_page_size);
7193
7194 273905 page_no_t size_in_pages = ((file->size / pages_per_mb) * pages_per_mb);
7195
7196
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 273901 times.
273905 if (space->id == TRX_SYS_SPACE) {
7197
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 srv_sys_space.set_last_file_size(size_in_pages);
7198
3/4
✓ Branch 0 taken 273901 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90504 times.
✓ Branch 3 taken 183397 times.
273901 } else if (fsp_is_system_temporary(space->id)) {
7199
1/2
✓ Branch 0 taken 90504 times.
✗ Branch 1 not taken.
90504 srv_tmp_space.set_last_file_size(size_in_pages);
7200 }
7201 #else /* !UNIV_HOTBACKUP */
7202 ib::trace_2() << "Extended space : " << space->name << " from " << prev_size
7203 << " pages to " << space->size << " pages "
7204 << ", desired space size : " << size << " pages";
7205 #endif /* !UNIV_HOTBACKUP */
7206
7207
1/2
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
273905 space_flush(space->id);
7208
7209
1/2
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
273905 mutex_release();
7210
7211
2/6
✓ Branch 0 taken 273905 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273905 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
273905 DBUG_EXECUTE_IF("fil_crash_after_extend", DBUG_SUICIDE(););
7212 273905 return success;
7213 }
7214
7215 /** Try to extend a tablespace if it is smaller than the specified size.
7216 @param[in,out] space Tablespace ID
7217 @param[in] size desired size in pages
7218 @return whether the tablespace is at least as big as requested */
7219 273924 bool fil_space_extend(fil_space_t *space, page_no_t size) {
7220 273924 auto shard = fil_system->shard_by_id(space->id);
7221
7222 273924 return shard->space_extend(space, size);
7223 }
7224
7225 #ifdef UNIV_HOTBACKUP
7226 /** Extends all tablespaces to the size stored in the space header. During the
7227 mysqlbackup --apply-log phase we extended the spaces on-demand so that log
7228 records could be applied, but that may have left spaces still too small
7229 compared to the size stored in the space header. */
7230 void Fil_shard::meb_extend_tablespaces_to_stored_len() {
7231 ut_ad(mutex_owned());
7232
7233 byte *buf = static_cast<byte *>(
7234 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, UNIV_PAGE_SIZE));
7235
7236 ut_a(buf != nullptr);
7237
7238 for (auto &elem : m_spaces) {
7239 auto space = elem.second;
7240
7241 ut_a(space->purpose == FIL_TYPE_TABLESPACE);
7242
7243 /* No need to protect with a mutex, because this is
7244 a single-threaded operation */
7245
7246 mutex_release();
7247
7248 dberr_t error;
7249
7250 const page_size_t page_size(space->flags);
7251
7252 error = fil_read(page_id_t(space->id, 0), page_size, 0,
7253 page_size.physical(), buf);
7254
7255 ut_a(error == DB_SUCCESS);
7256
7257 ulint size_in_header;
7258
7259 size_in_header = fsp_header_get_field(buf, FSP_SIZE);
7260
7261 bool success;
7262
7263 success = space_extend(space, size_in_header);
7264
7265 if (!success) {
7266 ib::error(ER_IB_MSG_321)
7267 << "Could not extend the tablespace of " << space->name
7268 << " to the size stored in"
7269 " header, "
7270 << size_in_header
7271 << " pages;"
7272 " size after extension "
7273 << 0
7274 << " pages. Check that you have free disk"
7275 " space and retry!";
7276
7277 ut_a(success);
7278 }
7279
7280 mutex_acquire();
7281 }
7282
7283 ut::free(buf);
7284 }
7285
7286 /** Extends all tablespaces to the size stored in the space header. During the
7287 mysqlbackup --apply-log phase we extended the spaces on-demand so that log
7288 records could be applied, but that may have left spaces still too small
7289 compared to the size stored in the space header. */
7290 void meb_extend_tablespaces_to_stored_len() {
7291 fil_system->meb_extend_tablespaces_to_stored_len();
7292 }
7293
7294 bool meb_is_redo_log_only_restore = false;
7295
7296 /** Determine if file is intermediate / temporary. These files are
7297 created during reorganize partition, rename tables, add / drop columns etc.
7298 @param[in] filepath absolute / relative or simply file name
7299 @retvalue true if it is intermediate file
7300 @retvalue false if it is normal file */
7301 bool meb_is_intermediate_file(const std::string &filepath) {
7302 std::string file_name = filepath;
7303
7304 {
7305 /** If its redo only restore, apply log needs to got through the
7306 intermediate steps to apply a ddl.
7307 Some of these operation might result in intermediate files.
7308 */
7309 if (meb_is_redo_log_only_restore) return false;
7310 /* extract file name from relative or absolute file name */
7311 auto pos = file_name.rfind(OS_PATH_SEPARATOR);
7312
7313 if (pos != std::string::npos) {
7314 ++pos;
7315 file_name = file_name.substr(pos);
7316 }
7317 }
7318
7319 transform(file_name.begin(), file_name.end(), file_name.begin(), ::tolower);
7320
7321 if (file_name[0] != '#') {
7322 auto pos = file_name.rfind("#tmp#.ibd");
7323 if (pos != std::string::npos) {
7324 return true;
7325 } else {
7326 return false; /* normal file name */
7327 }
7328 }
7329
7330 static std::vector<std::string> prefixes = {"#sql-", "#sql2-", "#tmp#",
7331 "#ren#"};
7332
7333 /* search for the unsupported patterns */
7334 for (const auto &prefix : prefixes) {
7335 if (Fil_path::has_prefix(file_name, prefix)) {
7336 return true;
7337 }
7338 }
7339
7340 return false;
7341 }
7342
7343 /** Return the space ID based of the remote general tablespace name.
7344 This is a wrapper over fil_space_get_id_by_name() method. it means,
7345 the tablespace must be found in the tablespace memory cache.
7346 This method extracts the tablespace name from input parameters and checks if
7347 it has been loaded in memory cache through either any of the remote general
7348 tablespaces directories identified at the time memory cache created.
7349 @param[in, out] tablespace Tablespace name
7350 @return space ID if tablespace found, SPACE_UNKNOWN if not found. */
7351 space_id_t meb_fil_space_get_rem_gen_ts_id_by_name(std::string &tablespace) {
7352 space_id_t space_id = SPACE_UNKNOWN;
7353
7354 for (auto newpath : rem_gen_ts_dirs) {
7355 auto pos = tablespace.rfind(OS_PATH_SEPARATOR);
7356
7357 if (pos == std::string::npos) {
7358 break;
7359 }
7360
7361 newpath += tablespace.substr(pos);
7362
7363 space_id = fil_space_get_id_by_name(newpath.c_str());
7364
7365 if (space_id != SPACE_UNKNOWN) {
7366 tablespace = newpath;
7367 break;
7368 }
7369 }
7370
7371 return space_id;
7372 }
7373
7374 /** Tablespace item during recovery */
7375 struct MEB_file_name {
7376 /** Constructor */
7377 MEB_file_name(std::string name, bool deleted)
7378 : m_name(name), m_space(), m_deleted(deleted) {}
7379
7380 /** Tablespace file name (MLOG_FILE_NAME) */
7381 std::string m_name;
7382
7383 /** Tablespace object (NULL if not valid or not found) */
7384 fil_space_t *m_space;
7385
7386 /** Whether the tablespace has been deleted */
7387 bool m_deleted;
7388 };
7389
7390 /** Map of dirty tablespaces during recovery */
7391 using MEB_recv_spaces =
7392 std::map<space_id_t, MEB_file_name, std::less<space_id_t>,
7393 ut::allocator<std::pair<const space_id_t, MEB_file_name>>>;
7394
7395 static MEB_recv_spaces recv_spaces;
7396
7397 /** Checks if MEB has loaded this space for reovery.
7398 @param[in] space_id Tablespace ID
7399 @return true if the space_id is loaded */
7400 bool meb_is_space_loaded(const space_id_t space_id) {
7401 return (recv_spaces.find(space_id) != recv_spaces.end());
7402 }
7403
7404 /** Set the keys for an encrypted tablespace.
7405 @param[in] space Tablespace for which to set the key */
7406 static void meb_set_encryption_key(const fil_space_t *space) {
7407 ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags));
7408
7409 for (auto &key : *recv_sys->keys) {
7410 if (key.space_id != space->id) {
7411 continue;
7412 }
7413
7414 dberr_t err;
7415
7416 err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv);
7417
7418 if (err != DB_SUCCESS) {
7419 ib::error(ER_IB_MSG_322) << "Can't set encryption information"
7420 << " for tablespace" << space->name << "!";
7421 }
7422
7423 ut::free(key.iv);
7424 ut::free(key.ptr);
7425
7426 key.iv = nullptr;
7427 key.ptr = nullptr;
7428 key.space_id = 0;
7429 }
7430 }
7431
7432 /** Process a file name passed as an input
7433 Wrapper around meb_name_process()
7434 @param[in,out] name absolute path of tablespace file
7435 @param[in] space_id The tablespace ID
7436 @param[in] deleted true if MLOG_FILE_DELETE */
7437 void Fil_system::meb_name_process(char *name, space_id_t space_id,
7438 bool deleted) {
7439 ut_ad(space_id != TRX_SYS_SPACE);
7440
7441 /* We will also insert space=nullptr into the map, so that
7442 further checks can ensure that a MLOG_FILE_NAME record was
7443 scanned before applying any page records for the space_id. */
7444
7445 Fil_path::normalize(name);
7446
7447 size_t len = std::strlen(name);
7448
7449 MEB_file_name fname(std::string(name, len - 1), deleted);
7450
7451 auto p = recv_spaces.insert(std::make_pair(space_id, fname));
7452
7453 ut_ad(p.first->first == space_id);
7454
7455 MEB_file_name &f = p.first->second;
7456
7457 if (deleted) {
7458 /* Got MLOG_FILE_DELETE */
7459
7460 if (!p.second && !f.m_deleted) {
7461 f.m_deleted = true;
7462
7463 if (f.m_space != nullptr) {
7464 f.m_space = nullptr;
7465 }
7466 }
7467
7468 ut_ad(f.m_space == nullptr);
7469
7470 } else if (p.second || f.m_name != fname.m_name) {
7471 fil_space_t *space;
7472
7473 /* Check if the tablespace file exists and contains
7474 the space_id. If not, ignore the file after displaying
7475 a note. Abort if there are multiple files with the
7476 same space_id. */
7477
7478 switch (ibd_open_for_recovery(space_id, name, space)) {
7479 case FIL_LOAD_OK:
7480 ut_ad(space != nullptr);
7481
7482 /* For encrypted tablespace, set key and iv. */
7483 if (FSP_FLAGS_GET_ENCRYPTION(space->flags) &&
7484 recv_sys->keys != nullptr) {
7485 meb_set_encryption_key(space);
7486 }
7487
7488 if (f.m_space == nullptr || f.m_space == space) {
7489 f.m_name = fname.m_name;
7490 f.m_space = space;
7491 f.m_deleted = false;
7492
7493 } else {
7494 ib::error(ER_IB_MSG_323)
7495 << "Tablespace " << space_id << " has been found in two places: '"
7496 << f.m_name << "' and '" << name
7497 << "'."
7498 " You must delete one of them.";
7499
7500 recv_sys->found_corrupt_fs = true;
7501 }
7502 break;
7503
7504 case FIL_LOAD_ID_CHANGED:
7505 ut_ad(space == nullptr);
7506
7507 ib::trace_1() << "Ignoring file " << name << " for space-id mismatch "
7508 << space_id;
7509 break;
7510
7511 case FIL_LOAD_NOT_FOUND:
7512 /* No matching tablespace was found; maybe it
7513 was renamed, and we will find a subsequent
7514 MLOG_FILE_* record. */
7515 ut_ad(space == nullptr);
7516 break;
7517
7518 case FIL_LOAD_INVALID:
7519 ut_ad(space == nullptr);
7520
7521 ib::warn(ER_IB_MSG_324) << "Invalid tablespace " << name;
7522 break;
7523
7524 case FIL_LOAD_MISMATCH:
7525 ut_ad(space == nullptr);
7526 break;
7527 case FIL_LOAD_DBWLR_CORRUPTION:
7528 ut_ad(space == nullptr);
7529 break;
7530 }
7531 }
7532 }
7533
7534 /** Process a file name passed as an input
7535 Wrapper around meb_name_process()
7536 @param[in] name absolute path of tablespace file
7537 @param[in] space_id the tablespace ID */
7538 void meb_fil_name_process(const char *name, space_id_t space_id) {
7539 char *file_name = static_cast<char *>(mem_strdup(name));
7540
7541 fil_system->meb_name_process(file_name, space_id, false);
7542
7543 ut::free(file_name);
7544 }
7545
7546 /** Test, if a file path name contains a back-link ("../").
7547 We assume a path to a file. So we don't check for a trailing "/..".
7548 @param[in] path path to check
7549 @return whether the path contains a back-link.
7550 */
7551 static bool meb_has_back_link(const std::string &path) {
7552 #ifdef _WIN32
7553 static const std::string DOT_DOT_SLASH = "..\\";
7554 static const std::string SLASH_DOT_DOT_SLASH = "\\..\\";
7555 #else
7556 static const std::string DOT_DOT_SLASH = "../";
7557 static const std::string SLASH_DOT_DOT_SLASH = "/../";
7558 #endif /* _WIN32 */
7559 return ((0 == path.compare(0, 3, DOT_DOT_SLASH)) ||
7560 (std::string::npos != path.find(SLASH_DOT_DOT_SLASH)));
7561 }
7562
7563 /** Parse a file name retrieved from a MLOG_FILE_* record,
7564 and return the absolute file path corresponds to backup dir
7565 as well as in the form of database/tablespace
7566 @param[in] name path emitted by the redo log
7567 @param[in] flags flags emitted by the redo log
7568 @param[in] space_id space_id emmited by the redo log
7569 @param[out] absolute_path absolute path of tablespace
7570 corresponds to target dir
7571 @param[out] tablespace_name name in the form of database/table */
7572 static void meb_make_abs_file_path(const std::string &name, uint32_t flags,
7573 space_id_t space_id,
7574 std::string &absolute_path,
7575 std::string &tablespace_name) {
7576 Datafile df;
7577 std::string file_name = name;
7578
7579 /* If the tablespace path name is absolute or has back-links ("../"),
7580 we assume, that it is located outside of datadir. */
7581 if (Fil_path::is_absolute_path(file_name.c_str()) ||
7582 (meb_has_back_link(file_name) && !replay_in_datadir)) {
7583 if (replay_in_datadir) {
7584 /* This is an apply-log in the restored datadir. Take the path as is. */
7585 df.set_filepath(file_name.c_str());
7586 } else {
7587 /* This is an apply-log in backup_dir/datadir. Get the file inside. */
7588 auto pos = file_name.rfind(OS_PATH_SEPARATOR);
7589
7590 /* if it is file per tablespace, then include the schema
7591 directory as well */
7592 if (fsp_is_file_per_table(space_id, flags) && pos != std::string::npos) {
7593 pos = file_name.rfind(OS_PATH_SEPARATOR, pos - 1);
7594 }
7595
7596 if (pos == std::string::npos) {
7597 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_325)
7598 << "Could not extract the tablespace"
7599 << " file name from the in the path : " << name;
7600 }
7601
7602 ++pos;
7603
7604 file_name = file_name.substr(pos);
7605
7606 df.make_filepath(MySQL_datadir_path, file_name.c_str(), IBD);
7607 }
7608
7609 } else {
7610 /* This is an apply-log with a relative path, either in the restored
7611 datadir, or in backup_dir/datadir. If in the restored datadir, the
7612 path might start with "../" to reach outside of datadir. */
7613 auto pos = file_name.find(OS_PATH_SEPARATOR);
7614
7615 /* Remove the cur dir from the path as this will cause the
7616 path name mismatch when we try to find out the space_id based
7617 on tablespace name */
7618
7619 if (file_name.substr(0, pos) == ".") {
7620 ++pos;
7621 file_name = file_name.substr(pos);
7622 }
7623
7624 /* make_filepath() does not prepend the directory, if the file name
7625 starts with "../". Prepend it unconditionally here. */
7626 file_name.insert(0, 1, OS_PATH_SEPARATOR);
7627 file_name.insert(0, MySQL_datadir_path);
7628
7629 df.make_filepath(nullptr, file_name.c_str(), IBD);
7630 }
7631
7632 df.set_flags(flags);
7633 df.set_space_id(space_id);
7634 df.set_name(nullptr);
7635
7636 absolute_path = df.filepath();
7637
7638 tablespace_name = df.name();
7639 }
7640
7641 /** Process a MLOG_FILE_CREATE redo record.
7642 @param[in] page_id Page id of the redo log record
7643 @param[in] flags Tablespace flags
7644 @param[in] name Tablespace filename */
7645 static void meb_tablespace_redo_create(const page_id_t &page_id, uint32_t flags,
7646 const char *name) {
7647 std::string abs_file_path;
7648 std::string tablespace_name;
7649
7650 meb_make_abs_file_path(name, flags, page_id.space(), abs_file_path,
7651 tablespace_name);
7652
7653 if (meb_is_intermediate_file(abs_file_path.c_str()) ||
7654 fil_space_get(page_id.space()) ||
7655 fil_space_get_id_by_name(tablespace_name.c_str()) != SPACE_UNKNOWN ||
7656 meb_fil_space_get_rem_gen_ts_id_by_name(tablespace_name) !=
7657 SPACE_UNKNOWN) {
7658 /* Don't create table while :-
7659 1. scanning the redo logs during backup
7660 2. apply-log on a partial backup
7661 3. if it is intermediate file
7662 4. tablespace is already loaded in memory
7663 5. tablespace is a remote general tablespace which is
7664 already loaded for recovery/apply-log from different
7665 directory path */
7666
7667 ib::trace_1() << "Ignoring the log record. No need to "
7668 << "create the tablespace : " << abs_file_path;
7669 } else {
7670 auto it = recv_spaces.find(page_id.space());
7671
7672 if (it == recv_spaces.end() || it->second.m_name != abs_file_path) {
7673 ib::trace_1() << "Creating the tablespace : " << abs_file_path
7674 << ", space_id : " << page_id.space();
7675
7676 dberr_t ret = fil_ibd_create(page_id.space(), tablespace_name.c_str(),
7677 abs_file_path.c_str(), flags,
7678 FIL_IBD_FILE_INITIAL_SIZE);
7679
7680 if (ret != DB_SUCCESS) {
7681 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_326)
7682 << "Could not create the tablespace : " << abs_file_path
7683 << " with space Id : " << page_id.space();
7684 }
7685 }
7686 }
7687 }
7688
7689 /** Process a MLOG_FILE_RENAME redo record.
7690 @param[in] page_id Page id of the redo log record
7691 @param[in] from_name Tablespace from filename
7692 @param[in] to_name Tablespace to filename */
7693 static void meb_tablespace_redo_rename(const page_id_t &page_id,
7694 const char *from_name,
7695 const char *to_name) {
7696 std::string abs_to_path;
7697 std::string abs_from_path;
7698 std::string tablespace_name;
7699
7700 meb_make_abs_file_path(from_name, 0, page_id.space(), abs_from_path,
7701 tablespace_name);
7702
7703 meb_make_abs_file_path(to_name, 0, page_id.space(), abs_to_path,
7704 tablespace_name);
7705
7706 char *new_name = nullptr;
7707
7708 if (meb_is_intermediate_file(from_name) ||
7709 meb_is_intermediate_file(to_name) ||
7710 fil_space_get_id_by_name(tablespace_name.c_str()) != SPACE_UNKNOWN ||
7711 meb_fil_space_get_rem_gen_ts_id_by_name(tablespace_name) !=
7712 SPACE_UNKNOWN ||
7713 fil_space_get(page_id.space()) == nullptr) {
7714 /* Don't rename table while :
7715 1. Scanning the redo logs during backup
7716 2. Apply-log on a partial backup
7717 3. Either of old or new tables are intermediate table
7718 4. The new name is already loaded for recovery/apply-log
7719 5. The new name is a remote general tablespace which is
7720 already loaded for recovery/apply-log from different
7721 directory path
7722 6. Tablespace is not yet loaded in memory.
7723 This will prevent unintended renames during recovery. */
7724
7725 ib::trace_1() << "Ignoring the log record. "
7726 << "No need to rename tablespace";
7727
7728 return;
7729
7730 } else {
7731 ib::trace_1() << "Renaming space id : " << page_id.space()
7732 << ", old tablespace name : " << from_name
7733 << " to new tablespace name : " << to_name;
7734
7735 new_name = static_cast<char *>(mem_strdup(abs_to_path.c_str()));
7736 }
7737
7738 meb_fil_name_process(from_name, page_id.space());
7739 meb_fil_name_process(new_name, page_id.space());
7740
7741 if (!fil_op_replay_rename(page_id, abs_from_path.c_str(),
7742 abs_to_path.c_str())) {
7743 recv_sys->found_corrupt_fs = true;
7744 }
7745
7746 meb_fil_name_process(to_name, page_id.space());
7747
7748 ut::free(new_name);
7749 }
7750
7751 /** Process a MLOG_FILE_DELETE redo record.
7752 @param[in] page_id Page id of the redo log record
7753 @param[in] name Tablespace filename */
7754 static void meb_tablespace_redo_delete(const page_id_t &page_id,
7755 const char *name) {
7756 std::string abs_file_path;
7757 std::string tablespace_name;
7758
7759 meb_make_abs_file_path(name, 0, page_id.space(), abs_file_path,
7760 tablespace_name);
7761
7762 char *file_name = static_cast<char *>(mem_strdup(name));
7763
7764 fil_system->meb_name_process(file_name, page_id.space(), true);
7765
7766 if (fil_space_get(page_id.space())) {
7767 ib::trace_1() << "Deleting the tablespace : " << abs_file_path
7768 << ", space_id : " << page_id.space();
7769 dberr_t err =
7770 fil_delete_tablespace(page_id.space(), BUF_REMOVE_FLUSH_NO_WRITE);
7771
7772 ut_a(err == DB_SUCCESS);
7773 }
7774
7775 ut::free(file_name);
7776 }
7777
7778 #endif /* UNIV_HOTBACKUP */
7779
7780 /*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/
7781
7782 /** Tries to reserve free extents in a file space.
7783 @param[in] space_id Tablespace ID
7784 @param[in] n_free_now Number of free extents now
7785 @param[in] n_to_reserve How many one wants to reserve
7786 @return true if succeed */
7787 8945066 bool fil_space_reserve_free_extents(space_id_t space_id, ulint n_free_now,
7788 ulint n_to_reserve) {
7789 8945066 auto shard = fil_system->shard_by_id(space_id);
7790
7791 8945066 shard->mutex_acquire();
7792
7793 8945066 fil_space_t *space = shard->get_space_by_id(space_id);
7794
7795 bool success;
7796
7797
2/2
✓ Branch 0 taken 4308 times.
✓ Branch 1 taken 8940757 times.
8945065 if (space->n_reserved_extents + n_to_reserve > n_free_now) {
7798 4308 success = false;
7799 } else {
7800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8940756 times.
8940757 ut_a(n_to_reserve < std::numeric_limits<uint32_t>::max());
7801 8940756 space->n_reserved_extents += (uint32_t)n_to_reserve;
7802 8940756 success = true;
7803 }
7804
7805 8945064 shard->mutex_release();
7806
7807 8945066 return success;
7808 }
7809
7810 /** Releases free extents in a file space.
7811 @param[in] space_id Tablespace ID
7812 @param[in] n_reserved How many were reserved */
7813 10490416 void fil_space_release_free_extents(space_id_t space_id, ulint n_reserved) {
7814 10490416 auto shard = fil_system->shard_by_id(space_id);
7815
7816 10490420 shard->mutex_acquire();
7817
7818 10490418 fil_space_t *space = shard->get_space_by_id(space_id);
7819
7820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10490418 times.
10490417 ut_a(n_reserved < std::numeric_limits<uint32_t>::max());
7821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10490416 times.
10490418 ut_a(space->n_reserved_extents >= n_reserved);
7822
7823 10490416 space->n_reserved_extents -= (uint32_t)n_reserved;
7824
7825 10490416 shard->mutex_release();
7826 10490419 }
7827
7828 /** Gets the number of reserved extents. If the database is silent, this number
7829 should be zero.
7830 @param[in] space_id Tablespace ID
7831 @return the number of reserved extents */
7832 1889980 ulint fil_space_get_n_reserved_extents(space_id_t space_id) {
7833 1889980 auto shard = fil_system->shard_by_id(space_id);
7834
7835 1889982 shard->mutex_acquire();
7836
7837 1889981 fil_space_t *space = shard->get_space_by_id(space_id);
7838
7839 1889982 ulint n = space->n_reserved_extents;
7840
7841 1889982 shard->mutex_release();
7842
7843 1889982 return n;
7844 }
7845
7846 /*============================ FILE I/O ================================*/
7847
7848 63919162 bool Fil_shard::prepare_file_for_io(fil_node_t *file) {
7849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63919817 times.
63919162 ut_ad(mutex_owned());
7850
7851 63919817 fil_space_t *space = file->space;
7852
7853
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63919964 times.
63919817 if (space->is_deleted()) {
7854 return false;
7855 }
7856
7857
2/2
✓ Branch 0 taken 276820 times.
✓ Branch 1 taken 63643144 times.
63919964 if (!file->is_open) {
7858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 276820 times.
276820 ut_a(file->n_pending_ios == 0);
7859
7860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 276816 times.
276820 if (!open_file(file)) {
7861 return false;
7862 }
7863 }
7864
2/2
✓ Branch 0 taken 56952949 times.
✓ Branch 1 taken 6967011 times.
63919960 if (file->n_pending_ios == 0) {
7865 56952949 remove_from_LRU(file);
7866 }
7867
7868 63919737 ++file->n_pending_ios;
7869
7870 /* The file can't be in the LRU list. */
7871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63920104 times.
63919737 ut_ad(!ut_list_exists(m_LRU, file));
7872
7873 63920104 return true;
7874 }
7875
7876 /** If the tablespace is not on the unflushed list, add it.
7877 @param[in,out] space Tablespace to add */
7878 16006847 void Fil_shard::add_to_unflushed_list(fil_space_t *space) {
7879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16006912 times.
16006847 ut_ad(mutex_owned());
7880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16006907 times.
16006912 ut_a(space->purpose != FIL_TYPE_TEMPORARY);
7881
7882
2/2
✓ Branch 0 taken 7559625 times.
✓ Branch 1 taken 8447282 times.
16006907 if (!space->is_in_unflushed_spaces) {
7883 7559625 space->is_in_unflushed_spaces = true;
7884
7885 7559625 UT_LIST_ADD_FIRST(m_unflushed_spaces, space);
7886 }
7887 16006970 }
7888
7889 /** Note that a write IO has completed.
7890 @param[in,out] file File on which a write was completed */
7891 17881877 void Fil_shard::write_completed(fil_node_t *file) {
7892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17881881 times.
17881877 ut_ad(mutex_owned());
7893
7894 17881881 ++m_modification_counter;
7895
7896 17881881 file->modification_counter = m_modification_counter;
7897
7898
2/2
✓ Branch 0 taken 1874989 times.
✓ Branch 1 taken 16006844 times.
17881881 if (fil_disable_space_flushing(file->space)) {
7899 /* We don't need to keep track of not flushed changes as either:
7900 - user has explicitly disabled buffering,
7901 - or it is FIL_TYPE_TEMPORARY space and we don't ever flush these. */
7902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1874988 times.
1874989 ut_ad(!file->space->is_in_unflushed_spaces);
7903
7904 1874988 file->set_flushed();
7905
7906 } else {
7907 16006844 add_to_unflushed_list(file->space);
7908 }
7909 17882045 }
7910
7911 /** Updates the data structures when an I/O operation finishes. Updates the
7912 pending I/O's field in the file appropriately.
7913 @param[in] file Tablespace file
7914 @param[in] type Marks the file as modified type == WRITE */
7915 63920394 void Fil_shard::complete_io(fil_node_t *file, const IORequest &type) {
7916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63920375 times.
63920394 ut_ad(mutex_owned());
7917
7918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63920259 times.
63920375 ut_a(file->n_pending_ios > 0);
7919
7920 63920259 --file->n_pending_ios;
7921
7922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63920143 times.
63920259 ut_ad(type.validate());
7923
7924
2/2
✓ Branch 0 taken 17881914 times.
✓ Branch 1 taken 46038321 times.
63920143 if (type.is_write()) {
7925
4/6
✓ Branch 0 taken 5774 times.
✓ Branch 1 taken 17876140 times.
✓ Branch 2 taken 5774 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17881894 times.
17881914 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(file->space->id));
7926
7927 17881894 write_completed(file);
7928 }
7929
7930
2/2
✓ Branch 0 taken 56953359 times.
✓ Branch 1 taken 6967009 times.
63920368 if (file->n_pending_ios == 0) {
7931 /* The file must be put back to the LRU list */
7932 56953359 add_to_lru_if_needed(file);
7933 }
7934 63920410 }
7935
7936 /** Report information about an invalid page access.
7937 @param[in] block_offset Block offset
7938 @param[in] space_id Tablespace ID
7939 @param[in] space_name Tablespace name
7940 @param[in] byte_offset Byte offset
7941 @param[in] len I/O length
7942 @param[in] is_read I/O type
7943 @param[in] line Line called from */
7944 static void fil_report_invalid_page_access_low(page_no_t block_offset,
7945 space_id_t space_id,
7946 const char *space_name,
7947 ulint byte_offset, ulint len,
7948 bool is_read, int line) {
7949 ib::error(ER_IB_MSG_328)
7950 << "Trying to access page number " << block_offset
7951 << " in"
7952 " space "
7953 << space_id << ", space name " << space_name
7954 << ","
7955 " which is outside the tablespace bounds. Byte offset "
7956 << byte_offset << ", len " << len << ", i/o type "
7957 << (is_read ? "read" : "write")
7958 << ". If you get this error at mysqld startup, please check"
7959 " that your my.cnf matches the ibdata files that you have in"
7960 " the MySQL server.";
7961
7962 ib::error(ER_IB_MSG_329) << "Server exits"
7963 #ifdef UNIV_DEBUG
7964 << " at "
7965 << "fil0fil.cc"
7966 << "[" << line << "]"
7967 #endif /* UNIV_DEBUG */
7968 << ".";
7969
7970 ut_error;
7971 }
7972
7973 #define fil_report_invalid_page_access(b, s, n, o, l, t) \
7974 fil_report_invalid_page_access_low((b), (s), (n), (o), (l), (t), __LINE__)
7975
7976 /** Set encryption information for IORequest.
7977 @param[in,out] req_type IO request
7978 @param[in] page_id page id
7979 @param[in] space table space */
7980 63613788 void fil_io_set_encryption(IORequest &req_type, const page_id_t &page_id,
7981 fil_space_t *space) {
7982 // TODO: now that dblwr doesn't exist in sys , should we encrypt all pages?
7983 // Or is there performance impact by encrypting TRX_SYS_PAGE which is
7984 // modified on every trx commit (binlog position is written)
7985
7986 /* Don't encrypt pages of system tablespace upto TRX_SYS_PAGE(including). The
7987 doublewrite buffer header is on TRX_SYS_PAGE */
7988
8/8
✓ Branch 0 taken 1141000 times.
✓ Branch 1 taken 62472860 times.
✓ Branch 2 taken 1140790 times.
✓ Branch 3 taken 210 times.
✓ Branch 4 taken 952794 times.
✓ Branch 5 taken 187996 times.
✓ Branch 6 taken 952794 times.
✓ Branch 7 taken 62661066 times.
64754578 if (fsp_is_system_tablespace(space->id) && space->crypt_data == nullptr &&
7989 1140790 page_id.page_no() <= FSP_TRX_SYS_PAGE_NO) {
7990 952794 req_type.clear_encrypted();
7991 952794 return;
7992 }
7993
7994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62661037 times.
62661066 ut_a(!req_type.is_log());
7995 /* Don't encrypt page 0 of all tablespaces except redo log
7996 tablespace, all pages from the system tablespace. */
7997
2/2
✓ Branch 0 taken 53647 times.
✓ Branch 1 taken 27194 times.
80841 if ((space->encryption_op_in_progress == Encryption::Progress::DECRYPTION &&
7998 80841 req_type.is_write()) ||
7999
8/8
✓ Branch 0 taken 80841 times.
✓ Branch 1 taken 62580196 times.
✓ Branch 2 taken 1073730 times.
✓ Branch 3 taken 61560142 times.
✓ Branch 4 taken 6748 times.
✓ Branch 5 taken 1066982 times.
✓ Branch 6 taken 61594117 times.
✓ Branch 7 taken 1066949 times.
62741878 !space->can_encrypt() || page_id.page_no() == 0) {
8000 61594117 req_type.clear_encrypted();
8001 61594113 return;
8002 }
8003
8004 /* For writing temporary tablespace, if encryption for temporary
8005 tablespace is disabled, skip setting encryption.
8006 Encryption of session temporary tablespaces is independent of
8007 innodb_temp_tablespace_encrypt */
8008
8/8
✓ Branch 0 taken 2342 times.
✓ Branch 1 taken 1064640 times.
✓ Branch 2 taken 156 times.
✓ Branch 3 taken 2186 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 118 times.
✓ Branch 6 taken 38 times.
✓ Branch 7 taken 1066944 times.
1067105 if (fsp_is_global_temporary(space->id) && !srv_tmp_tablespace_encrypt &&
8009 156 req_type.is_write()) {
8010 38 req_type.clear_encrypted();
8011 38 return;
8012 }
8013
8014 /* For writing undo log, if encryption for undo log is disabled,
8015 skip set encryption. */
8016
8/8
✓ Branch 0 taken 764791 times.
✓ Branch 1 taken 302153 times.
✓ Branch 2 taken 80125 times.
✓ Branch 3 taken 684666 times.
✓ Branch 4 taken 6550 times.
✓ Branch 5 taken 73575 times.
✓ Branch 6 taken 6550 times.
✓ Branch 7 taken 1060394 times.
1147069 if (fsp_is_undo_tablespace(space->id) && !srv_undo_log_encrypt &&
8017 80125 req_type.is_write()) {
8018 6550 req_type.clear_encrypted();
8019 6550 return;
8020 }
8021
8022
2/2
✓ Branch 0 taken 428784 times.
✓ Branch 1 taken 631610 times.
1060394 if (req_type.get_encrypted_block() != nullptr) {
8023 /* Already encrypted. */
8024 428784 req_type.clear_encrypted();
8025 428786 return;
8026 }
8027
8028 631610 req_type.encryption_key(space->m_encryption_metadata.m_key,
8029 space->m_encryption_metadata.m_key_len,
8030 631610 space->m_encryption_metadata.m_iv);
8031
8032 631610 req_type.encryption_algorithm(Encryption::AES);
8033 }
8034
8035 63613635 AIO_mode Fil_shard::get_AIO_mode(const IORequest &, bool sync) {
8036 #ifndef UNIV_HOTBACKUP
8037
2/2
✓ Branch 0 taken 45215294 times.
✓ Branch 1 taken 18398341 times.
63613635 if (sync) {
8038 45215294 return AIO_mode::SYNC;
8039
8040 } else {
8041 18398341 return AIO_mode::NORMAL;
8042 }
8043 #else /* !UNIV_HOTBACKUP */
8044 ut_a(sync);
8045 return AIO_mode::SYNC;
8046 #endif /* !UNIV_HOTBACKUP */
8047 }
8048
8049 63613808 dberr_t Fil_shard::get_file_for_io(fil_space_t *space, page_no_t *page_no,
8050 fil_node_t *&file) {
8051 63613808 file = space->get_file_node(page_no);
8052
2/2
✓ Branch 0 taken 959 times.
✓ Branch 1 taken 63613415 times.
63614374 return (file == nullptr) ? DB_ERROR : DB_SUCCESS;
8053 }
8054
8055 63613891 dberr_t Fil_shard::do_io(const IORequest &type, bool sync,
8056 const page_id_t &page_id, const page_size_t &page_size,
8057 ulint byte_offset, ulint len, void *buf, void *message,
8058 trx_t *trx, bool should_buffer) {
8059 63613891 IORequest req_type(type);
8060
8061
2/4
✓ Branch 0 taken 63615285 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63615087 times.
63614383 ut_ad(req_type.validate());
8062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63614654 times.
63615087 ut_ad(!req_type.is_log());
8063
8064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63614302 times.
63614654 ut_ad(len > 0);
8065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63613703 times.
63614302 ut_ad(byte_offset < UNIV_PAGE_SIZE);
8066
4/6
✓ Branch 0 taken 73208 times.
✓ Branch 1 taken 63540709 times.
✓ Branch 2 taken 73208 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63613660 times.
63613703 ut_ad(!page_size.is_compressed() || byte_offset == 0);
8067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63613805 times.
63613660 ut_ad(UNIV_PAGE_SIZE == (ulong)(1 << UNIV_PAGE_SIZE_SHIFT));
8068
8069
2/4
✓ Branch 0 taken 63613525 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63613525 times.
63613805 ut_ad(fil_validate_skip());
8070
8071 #ifndef UNIV_HOTBACKUP
8072 /* ibuf bitmap pages must be read in the sync AIO mode: */
8073
9/12
✓ Branch 0 taken 63528205 times.
✓ Branch 1 taken 85320 times.
✓ Branch 2 taken 45954137 times.
✓ Branch 3 taken 17574291 times.
✓ Branch 4 taken 45954237 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 93355 times.
✓ Branch 7 taken 45860882 times.
✓ Branch 8 taken 93355 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 63613935 times.
63613525 ut_ad(recv_no_ibuf_operations || req_type.is_write() ||
8074 !ibuf_bitmap_page(page_id, page_size) || sync);
8075
8076
1/2
✓ Branch 0 taken 63613962 times.
✗ Branch 1 not taken.
63613935 auto aio_mode = get_AIO_mode(req_type, sync);
8077
8078
2/2
✓ Branch 0 taken 46006854 times.
✓ Branch 1 taken 17607199 times.
63613962 if (req_type.is_read()) {
8079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46006881 times.
46006854 ut_ad(type.get_original_size() == 0);
8080
1/2
✓ Branch 0 taken 46006859 times.
✗ Branch 1 not taken.
46006881 srv_stats.data_read.add(len);
8081
8082
6/6
✓ Branch 0 taken 941443 times.
✓ Branch 1 taken 45065416 times.
✓ Branch 2 taken 889547 times.
✓ Branch 3 taken 51896 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 46006857 times.
46896405 if (aio_mode == AIO_mode::NORMAL && !recv_no_ibuf_operations &&
8083
3/4
✓ Branch 0 taken 889546 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 889545 times.
889547 ibuf_page(page_id, page_size, UT_LOCATION_HERE, nullptr)) {
8084 /* Reduce probability of deadlock bugs
8085 in connection with ibuf: do not let the
8086 ibuf I/O handler sleep */
8087
8088 1 req_type.clear_do_not_wake();
8089
8090 1 aio_mode = AIO_mode::IBUF;
8091 }
8092
8093 #ifdef UNIV_DEBUG
8094
1/2
✓ Branch 0 taken 46006982 times.
✗ Branch 1 not taken.
46006858 mutex_acquire();
8095 /* Should never attempt to read from a deleted tablespace, unless we
8096 are also importing the tablespace. By the time we get here in the final
8097 phase of import the state has changed. Therefore we check if there is
8098 an active fil_space_t instance with the same ID. */
8099
2/2
✓ Branch 0 taken 363256 times.
✓ Branch 1 taken 46006977 times.
46370238 for (auto pair : m_deleted_spaces) {
8100
2/2
✓ Branch 0 taken 3296 times.
✓ Branch 1 taken 359960 times.
363256 if (pair.first == page_id.space()) {
8101
1/2
✓ Branch 0 taken 3296 times.
✗ Branch 1 not taken.
3296 auto space = get_space_by_id(page_id.space());
8102
1/2
✓ Branch 0 taken 3296 times.
✗ Branch 1 not taken.
3296 if (space != nullptr) {
8103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3296 times.
3296 ut_a(pair.second != space);
8104 }
8105 }
8106 }
8107
1/2
✓ Branch 0 taken 46006981 times.
✗ Branch 1 not taken.
46006977 mutex_release();
8108 #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
8109
8110
1/2
✓ Branch 0 taken 17607059 times.
✗ Branch 1 not taken.
17607199 } else if (req_type.is_write()) {
8111
5/8
✓ Branch 0 taken 5735 times.
✓ Branch 1 taken 17601324 times.
✓ Branch 2 taken 5841 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5841 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 17607032 times.
17607059 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(page_id.space()));
8112
8113
1/2
✓ Branch 0 taken 17606504 times.
✗ Branch 1 not taken.
17607032 srv_stats.data_written.add(len);
8114 }
8115 #else /* !UNIV_HOTBACKUP */
8116 ut_a(sync);
8117 auto aio_mode = AIO_mode::SYNC;
8118 #endif /* !UNIV_HOTBACKUP */
8119
8120 /* Reserve the mutex and make sure that we can open at
8121 least one file while holding it, if the file is not already open */
8122
8123 63613364 auto bpage = static_cast<buf_page_t *>(message);
8124
8125
1/2
✓ Branch 0 taken 63615736 times.
✗ Branch 1 not taken.
63613364 mutex_acquire();
8126
1/2
✓ Branch 0 taken 63615554 times.
✗ Branch 1 not taken.
63615736 auto space = get_space_by_id(page_id.space());
8127
8128 /* If we are deleting a tablespace we don't allow async read
8129 operations on that. However, we do allow write operations and
8130 sync read operations. */
8131
6/6
✓ Branch 0 taken 63614197 times.
✓ Branch 1 taken 1357 times.
✓ Branch 2 taken 46006978 times.
✓ Branch 3 taken 17607301 times.
✓ Branch 4 taken 1355 times.
✓ Branch 5 taken 63614281 times.
173236811 if (space == nullptr ||
8132
3/4
✓ Branch 0 taken 941443 times.
✓ Branch 1 taken 45065535 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 941445 times.
109621175 (req_type.is_read() && !sync && space->stop_new_ops)) {
8133 #ifndef UNIV_HOTBACKUP
8134
3/6
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1355 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1355 times.
✗ Branch 5 not taken.
1355 const auto is_page_stale = bpage != nullptr && bpage->is_stale();
8135 #endif /* !UNIV_HOTBACKUP */
8136
8137
1/2
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
1355 mutex_release();
8138
8139
1/2
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
1355 if (space == nullptr) {
8140 #ifndef UNIV_HOTBACKUP
8141
3/6
✓ Branch 0 taken 1355 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1355 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1355 times.
✗ Branch 5 not taken.
1355 if (req_type.is_write() && is_page_stale) {
8142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1355 times.
1355 ut_a(bpage->get_space()->id == page_id.space());
8143 1355 return DB_PAGE_IS_STALE;
8144 }
8145 #endif /* !UNIV_HOTBACKUP */
8146
8147 if (!req_type.ignore_missing()) {
8148 #ifndef UNIV_HOTBACKUP
8149 /* Don't have any record of this tablespace. print a warning. */
8150 if (!Fil_shard::is_deleted(page_id.space())) {
8151 #endif /* !UNIV_HOTBACKUP */
8152 if (space == nullptr) {
8153 ib::error(ER_IB_MSG_330)
8154 << "Trying to do I/O on a tablespace"
8155 << " which does not exist. I/O type: "
8156 << (req_type.is_read() ? "read" : "write")
8157 << ", page: " << page_id << ", I/O length: " << len << " bytes";
8158 } else {
8159 ib::error(ER_IB_MSG_331)
8160 << "Trying to do async read on a tablespace which is being"
8161 << " deleted. Tablespace name: \"" << space->name << "\","
8162 << " page: " << page_id << ", read length: " << len << " bytes";
8163 }
8164 #ifndef UNIV_HOTBACKUP
8165 }
8166 #endif /* !UNIV_HOTBACKUP */
8167 }
8168 }
8169
8170 return DB_TABLESPACE_DELETED;
8171 }
8172
8173 #ifndef UNIV_HOTBACKUP
8174
2/2
✓ Branch 0 taken 62806649 times.
✓ Branch 1 taken 807632 times.
63614281 if (bpage != nullptr) {
8175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62807057 times.
62806649 ut_a(bpage->get_space()->id == page_id.space());
8176
8177
7/8
✓ Branch 0 taken 17598663 times.
✓ Branch 1 taken 45208468 times.
✓ Branch 2 taken 17598704 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 17598680 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 62807148 times.
62807057 if (req_type.is_write() && bpage->is_stale()) {
8178
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 mutex_release();
8179 24 return DB_PAGE_IS_STALE;
8180 }
8181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62807061 times.
62807148 ut_a(bpage->get_space() == space);
8182 }
8183 #endif /* !UNIV_HOTBACKUP */
8184
8185 fil_node_t *file;
8186 63614693 auto page_no = page_id.page_no();
8187
1/2
✓ Branch 0 taken 63614381 times.
✗ Branch 1 not taken.
63613755 auto err = get_file_for_io(space, &page_no, file);
8188
8189
2/2
✓ Branch 0 taken 959 times.
✓ Branch 1 taken 63613422 times.
63614381 if (file == nullptr) {
8190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 959 times.
959 ut_ad(err == DB_ERROR);
8191
8192
1/2
✓ Branch 0 taken 959 times.
✗ Branch 1 not taken.
959 if (req_type.ignore_missing()) {
8193
1/2
✓ Branch 0 taken 959 times.
✗ Branch 1 not taken.
959 mutex_release();
8194
8195 959 return DB_ERROR;
8196 }
8197
8198 #ifndef UNIV_HOTBACKUP
8199 if (req_type.is_write() && bpage != nullptr && bpage->is_stale()) {
8200 ut_a(bpage->get_space()->id == page_id.space());
8201
8202 mutex_release();
8203 return DB_PAGE_IS_STALE;
8204 }
8205 #endif /* !UNIV_HOTBACKUP */
8206
8207 /* This is a hard error. */
8208 fil_report_invalid_page_access(page_id.page_no(), page_id.space(),
8209 space->name, byte_offset, len,
8210 req_type.is_read());
8211 }
8212
8213 #ifndef UNIV_HOTBACKUP
8214
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 63613179 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63613179 times.
63613179 if (UNIV_UNLIKELY(space->is_corrupt && srv_pass_corrupt_table)) {
8215 /* should ignore i/o for the crashed space */
8216 if (srv_pass_corrupt_table == 1 || req_type.is_write()) {
8217 complete_io(file, type);
8218 if (aio_mode == AIO_mode::NORMAL) {
8219 ut_a(space->purpose == FIL_TYPE_TABLESPACE);
8220 buf_page_io_complete(static_cast<buf_page_t *>(message), false);
8221 }
8222 }
8223
8224 if (srv_pass_corrupt_table == 1 && req_type.is_read())
8225 return (DB_TABLESPACE_DELETED);
8226 else if (req_type.is_write())
8227 return (DB_SUCCESS);
8228 }
8229 #endif
8230
8231
2/4
✓ Branch 0 taken 63613363 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63613363 times.
63613179 if (!prepare_file_for_io(file)) {
8232 #ifndef UNIV_HOTBACKUP
8233 if (space->is_deleted()) {
8234 mutex_release();
8235
8236 if (!sync) {
8237 ut_d(bpage->take_io_responsibility());
8238 buf_page_io_complete(bpage, false);
8239 }
8240
8241 return DB_TABLESPACE_DELETED;
8242 }
8243 #endif /* !UNIV_HOTBACKUP */
8244
8245 if (fsp_is_ibd_tablespace(space->id)) {
8246 mutex_release();
8247
8248 if (!req_type.ignore_missing()) {
8249 ib::error(ER_IB_MSG_332)
8250 << "Trying to do I/O to a tablespace"
8251 " which exists without an .ibd data"
8252 << " file. I/O type: " << (req_type.is_read() ? "read" : "write")
8253 << ", page: " << page_id_t(page_id.space(), page_no)
8254 << ", I/O length: " << len << " bytes";
8255 }
8256
8257 return DB_TABLESPACE_DELETED;
8258 }
8259
8260 /* Could not open a file to perform IO and this is not a IBD file,
8261 which could have become deleted meanwhile. This is a fatal error.
8262 Note: any log information should be emitted inside prepare_file_for_io()
8263 called few lines earlier. That's because the specific reason for this
8264 problem is known only inside there. */
8265 ut_error;
8266 }
8267
8268 /* Check that at least the start offset is within the bounds of a
8269 single-table tablespace, including rollback tablespaces. */
8270
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 63613361 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
63613363 if (file->size <= page_no && space->id != TRX_SYS_SPACE) {
8271 #ifndef UNIV_HOTBACKUP
8272
2/10
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
2 if (req_type.is_write() && bpage != nullptr && bpage->is_stale()) {
8273 ut_a(bpage->get_space()->id == page_id.space());
8274 return DB_PAGE_IS_STALE;
8275 }
8276 #endif /* !UNIV_HOTBACKUP */
8277
8278
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (req_type.ignore_missing()) {
8279 /* If we can tolerate the non-existent pages, we
8280 should return with DB_ERROR and let caller decide
8281 what to do. */
8282
8283
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 complete_io(file, req_type);
8284
8285
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_release();
8286
8287 2 return DB_ERROR;
8288 }
8289
8290 /* This is a hard error. */
8291 fil_report_invalid_page_access(page_id.page_no(), page_id.space(),
8292 space->name, byte_offset, len,
8293 req_type.is_read());
8294 }
8295
8296
1/2
✓ Branch 0 taken 63613346 times.
✗ Branch 1 not taken.
63613361 mutex_release();
8297
8298
3/4
✓ Branch 0 taken 61991867 times.
✓ Branch 1 taken 1621479 times.
✓ Branch 2 taken 61992407 times.
✗ Branch 3 not taken.
63613346 DEBUG_SYNC_C("innodb_fil_do_io_prepared_io_with_no_mutex");
8299
8300
6/10
✓ Branch 0 taken 63540897 times.
✓ Branch 1 taken 73208 times.
✓ Branch 2 taken 63540887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 63540796 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 63540796 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 63613897 times.
63613886 ut_a(page_size.is_compressed() ||
8301 page_size.physical() == page_size.logical());
8302
8303
1/2
✓ Branch 0 taken 63613835 times.
✗ Branch 1 not taken.
63613897 auto offset = (os_offset_t)page_no * page_size.physical();
8304
8305 63613835 offset += byte_offset;
8306
8307
3/6
✓ Branch 0 taken 63613759 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63613752 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63613755 times.
63613835 ut_a(file->size - page_no >=
8308 (byte_offset +
8309 std::max(static_cast<uint32_t>(len), type.get_original_size()) +
8310 (page_size.physical() - 1)) /
8311 page_size.physical());
8312
8313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63613582 times.
63613755 ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
8314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63613706 times.
63613582 ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
8315
8316 /* Don't compress the log, page 0 of all tablespaces, tables compressed with
8317 the old compression scheme and all pages from the system tablespace. */
8318
4/4
✓ Branch 0 taken 17562065 times.
✓ Branch 1 taken 45809 times.
✓ Branch 2 taken 17087549 times.
✓ Branch 3 taken 474531 times.
98783683 if (req_type.is_write() && !page_size.is_compressed() &&
8319
6/8
✓ Branch 0 taken 17607897 times.
✓ Branch 1 taken 46005811 times.
✓ Branch 2 taken 17087647 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17087650 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17087648 times.
✓ Branch 7 taken 46526150 times.
115871312 page_id.page_no() > 0 && IORequest::is_punch_hole_supported() &&
8320
1/2
✓ Branch 0 taken 17087652 times.
✗ Branch 1 not taken.
17087650 file->punch_hole) {
8321
1/2
✓ Branch 0 taken 17087647 times.
✗ Branch 1 not taken.
17087648 req_type.set_punch_hole();
8322
8323
1/2
✓ Branch 0 taken 17087652 times.
✗ Branch 1 not taken.
17087647 req_type.compression_algorithm(space->compression_type);
8324
8325 } else {
8326 46526150 req_type.clear_compressed();
8327 }
8328
8329
2/2
✓ Branch 0 taken 73193 times.
✓ Branch 1 taken 63540715 times.
63613923 if (page_size.is_compressed()) {
8330 73193 req_type.mark_page_zip_compressed();
8331
1/2
✓ Branch 0 taken 73193 times.
✗ Branch 1 not taken.
73193 req_type.set_zip_page_physical_size(page_size.physical());
8332
2/4
✓ Branch 0 taken 73193 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73193 times.
73193 ut_ad(page_size.physical() > 0);
8333 }
8334
8335 /* Set encryption information. */
8336
1/2
✓ Branch 0 taken 63613620 times.
✗ Branch 1 not taken.
63613908 fil_io_set_encryption(req_type, page_id, space);
8337
8338 63613620 req_type.block_size(file->block_size);
8339
8340 #ifdef UNIV_HOTBACKUP
8341 /* In mysqlbackup do normal I/O, not AIO */
8342 if (req_type.is_read()) {
8343 err = os_file_read(req_type, file->name, file->handle, buf, offset, len);
8344
8345 } else {
8346 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(page_id.space()));
8347
8348 err = os_file_write(req_type, file->name, file->handle, buf, offset, len);
8349 }
8350 #else /* UNIV_HOTBACKUP */
8351 /* Queue the aio request */
8352
4/6
✓ Branch 0 taken 63613715 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6904060 times.
✓ Branch 3 taken 56709655 times.
✓ Branch 4 taken 63613579 times.
✗ Branch 5 not taken.
63613879 err = os_aio(
8353 req_type, aio_mode, file->name, file->handle, buf, offset, len,
8354 fsp_is_system_temporary(page_id.space()) ? false : srv_read_only_mode,
8355 file, message, page_id.space(), trx, should_buffer);
8356
8357 #endif /* UNIV_HOTBACKUP */
8358
8359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63613579 times.
63613579 if (err == DB_IO_NO_PUNCH_HOLE) {
8360 err = DB_SUCCESS;
8361
8362 if (file->punch_hole) {
8363 ib::warn(ER_IB_MSG_333) << "Punch hole failed for '" << file->name << "'";
8364 }
8365
8366 fil_no_punch_hole(file);
8367 }
8368
8369 /* We an try to recover the page from the double write buffer if
8370 the decompression fails or the page is corrupt. */
8371
8372
4/8
✓ Branch 0 taken 62823660 times.
✓ Branch 1 taken 789438 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62823660 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 63613306 times.
63613579 ut_a(req_type.is_dblwr() || err == DB_SUCCESS || err == DB_IO_DECRYPT_FAIL);
8373
8374
2/2
✓ Branch 0 taken 45213897 times.
✓ Branch 1 taken 18399409 times.
63613306 if (sync) {
8375 /* The i/o operation is already completed when we return from
8376 os_aio: */
8377
8378
1/2
✓ Branch 0 taken 45214410 times.
✗ Branch 1 not taken.
45213897 mutex_acquire();
8379
8380
1/2
✓ Branch 0 taken 45214422 times.
✗ Branch 1 not taken.
45214410 complete_io(file, req_type);
8381
8382
1/2
✓ Branch 0 taken 45214436 times.
✗ Branch 1 not taken.
45214422 mutex_release();
8383
8384
3/4
✓ Branch 0 taken 45214426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 45214342 times.
45214436 ut_ad(fil_validate_skip());
8385 }
8386
8387 63613751 return err;
8388 63616091 }
8389
8390 #ifndef UNIV_HOTBACKUP
8391 /** Waits for an AIO operation to complete. This function is used to write the
8392 handler for completed requests. The aio array of pending requests is divided
8393 into segments (see os0file.cc for more info). The thread specifies which
8394 segment it wants to wait for.
8395 @param[in] segment The number of the segment in the AIO array
8396 to wait for */
8397 19010182 void fil_aio_wait(ulint segment) {
8398 void *m2;
8399 fil_node_t *m1;
8400 19010182 IORequest type;
8401
8402
2/4
✓ Branch 0 taken 19010548 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19010677 times.
19010737 ut_ad(fil_validate_skip());
8403
8404
1/2
✓ Branch 0 taken 18999558 times.
✗ Branch 1 not taken.
19010677 auto err = os_aio_handler(segment, &m1, &m2, &type);
8405
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 18999733 times.
18999558 ut_a(err == DB_SUCCESS);
8406
8407 18999733 auto file = reinterpret_cast<fil_node_t *>(m1);
8408
8409
2/2
✓ Branch 0 taken 600020 times.
✓ Branch 1 taken 18399713 times.
18999733 if (file == nullptr) {
8410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 599998 times.
600020 ut_ad(srv_shutdown_state.load() == SRV_SHUTDOWN_EXIT_THREADS);
8411 599998 return;
8412 }
8413
8414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18399766 times.
18399713 ut_a(!type.is_dblwr());
8415
8416
1/2
✓ Branch 0 taken 18399710 times.
✗ Branch 1 not taken.
18399766 srv_set_io_thread_op_info(segment, "complete io for file");
8417
8418
1/2
✓ Branch 0 taken 18399756 times.
✗ Branch 1 not taken.
18399710 auto shard = fil_system->shard_by_id(file->space->id);
8419
8420
1/2
✓ Branch 0 taken 18399698 times.
✗ Branch 1 not taken.
18399756 shard->mutex_acquire();
8421
8422
1/2
✓ Branch 0 taken 18399715 times.
✗ Branch 1 not taken.
18399698 shard->complete_io(file, type);
8423
8424
1/2
✓ Branch 0 taken 18399740 times.
✗ Branch 1 not taken.
18399715 shard->mutex_release();
8425
8426
3/4
✓ Branch 0 taken 18399702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 18399634 times.
18399740 ut_ad(fil_validate_skip());
8427
8428 /* Do the i/o handling */
8429 /* IMPORTANT: since i/o handling for reads will read also the insert
8430 buffer in tablespace 0, you have to be very careful not to introduce
8431 deadlocks in the i/o system. We keep tablespace 0 data files always
8432 open, and use a special i/o thread to serve insert buffer requests. */
8433
8434
1/2
✓ Branch 0 taken 18399634 times.
✗ Branch 1 not taken.
18399634 switch (file->space->purpose) {
8435 18399634 case FIL_TYPE_IMPORT:
8436 case FIL_TYPE_TEMPORARY:
8437 case FIL_TYPE_TABLESPACE:
8438
1/2
✓ Branch 0 taken 18399621 times.
✗ Branch 1 not taken.
18399634 srv_set_io_thread_op_info(segment, "complete io for buf page");
8439
8440 /* async single page writes from the dblwr buffer don't have
8441 access to the page */
8442
1/2
✓ Branch 0 taken 18399628 times.
✗ Branch 1 not taken.
18399621 if (m2 != nullptr) {
8443 18399628 auto bpage = static_cast<buf_page_t *>(m2);
8444
1/2
✓ Branch 0 taken 18399375 times.
✗ Branch 1 not taken.
18399628 ut_d(bpage->take_io_responsibility());
8445
1/2
✓ Branch 0 taken 18398197 times.
✗ Branch 1 not taken.
18399375 buf_page_io_complete(bpage, false);
8446 }
8447 18398190 return;
8448 }
8449
8450 ut_d(ut_error);
8451 18998188 }
8452 #endif /* !UNIV_HOTBACKUP */
8453
8454 /** Read or write data from a file.
8455 @param[in] type IO context
8456 @param[in] sync If true then do synchronous IO
8457 @param[in] page_id page id
8458 @param[in] page_size page size
8459 @param[in] byte_offset remainder of offset in bytes; in aio this
8460 must be divisible by the OS block size
8461 @param[in] len how many bytes to read or write; this must
8462 not cross a file boundary; in AIO this must
8463 be a block size multiple
8464 @param[in,out] buf buffer where to store read data or from where
8465 to write; in AIO this must be appropriately
8466 aligned
8467 @param[in] message message for AIO handler if !sync, else ignored
8468 @param[in] should_buffer whether to buffer an aio request. AIO read
8469 ahead uses this. If you plan to use this
8470 parameter, make sure you remember to call
8471 os_aio_dispatch_read_array_submit() when you're
8472 ready to commit all your requests.
8473 @return error code
8474 @retval DB_SUCCESS on success
8475 @retval DB_TABLESPACE_DELETED if the tablespace does not exist */
8476 63613086 dberr_t _fil_io(const IORequest &type, bool sync, const page_id_t &page_id,
8477 const page_size_t &page_size, ulint byte_offset, ulint len,
8478 void *buf, void *message, trx_t *trx, bool should_buffer) {
8479 63613086 auto shard = fil_system->shard_by_id(page_id.space());
8480 #ifdef UNIV_DEBUG
8481
2/2
✓ Branch 0 taken 18399693 times.
✓ Branch 1 taken 45214229 times.
63613922 if (!sync) {
8482 /* In case of async io we transfer the io responsibility to the thread which
8483 will perform the io completion routine. */
8484 18399693 static_cast<buf_page_t *>(message)->release_io_responsibility();
8485 }
8486 #endif
8487
8488 63613705 auto const err = shard->do_io(type, sync, page_id, page_size, byte_offset,
8489 len, buf, message, trx, should_buffer);
8490 #ifdef UNIV_DEBUG
8491 /* If the error prevented async io, then we haven't actually transfered the
8492 io responsibility at all, so we revert the debug io responsibility info. */
8493 63616045 auto bpage = static_cast<buf_page_t *>(message);
8494
8495 /* When space is deleted, we could have marked the io complete. */
8496
7/8
✓ Branch 0 taken 2340 times.
✓ Branch 1 taken 63613705 times.
✓ Branch 2 taken 1379 times.
✓ Branch 3 taken 961 times.
✓ Branch 4 taken 1379 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1379 times.
✓ Branch 7 taken 63614666 times.
63616045 if (err != DB_SUCCESS && !sync && bpage->was_io_fixed()) {
8497 1379 bpage->take_io_responsibility();
8498 }
8499 #endif
8500 63616196 return err;
8501 }
8502
8503 /** If the tablespace is on the unflushed list and there are no pending
8504 flushes then remove from the unflushed list.
8505 @param[in,out] space Tablespace to remove */
8506 8550971 void Fil_shard::remove_from_unflushed_list(fil_space_t *space) {
8507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8553006 times.
8550971 ut_ad(mutex_owned());
8508
8509
6/6
✓ Branch 0 taken 8551348 times.
✓ Branch 1 taken 1658 times.
✓ Branch 2 taken 7557499 times.
✓ Branch 3 taken 992104 times.
✓ Branch 4 taken 7557499 times.
✓ Branch 5 taken 993762 times.
8553006 if (space->is_in_unflushed_spaces && space_is_flushed(space)) {
8510 7557499 space->is_in_unflushed_spaces = false;
8511
8512 7557499 UT_LIST_REMOVE(m_unflushed_spaces, space);
8513 }
8514 8552345 }
8515
8516 9044196 void Fil_shard::space_flush(space_id_t space_id) {
8517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9044191 times.
9044196 ut_ad(mutex_owned());
8518
8519 9044191 fil_space_t *space = get_space_by_id(space_id);
8520
8521
4/4
✓ Branch 0 taken 9044161 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 8953049 times.
✓ Branch 3 taken 91112 times.
9044175 if (space == nullptr || space->purpose == FIL_TYPE_TEMPORARY ||
8522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8953051 times.
8953049 space->stop_new_ops) {
8523 91124 return;
8524 }
8525
8526 8953051 const bool disable_flush = fil_disable_space_flushing(space);
8527
8528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8953049 times.
8953049 if (disable_flush) {
8529 /* No need to flush. User has explicitly disabled
8530 buffering. However, flush should be called if the file
8531 size changes to keep OÐ… metadata in sync. */
8532 ut_ad(!space->is_in_unflushed_spaces);
8533 ut_ad(space_is_flushed(space));
8534
8535 /* Flush only if the file size changes */
8536 bool no_flush = true;
8537 for (const auto &file : space->files) {
8538 #ifdef UNIV_DEBUG
8539 ut_ad(file.is_flushed());
8540 #endif /* UNIV_DEBUG */
8541 if (file.flush_size != file.size) {
8542 /* Found at least one file whose size has changed */
8543 no_flush = false;
8544 break;
8545 }
8546 }
8547
8548 if (no_flush) {
8549 /* Nothing to flush. Just return */
8550 return;
8551 }
8552 }
8553
8554 /* Prevent dropping of the space while we are flushing */
8555 8953049 ++space->n_pending_flushes;
8556
8557
2/2
✓ Branch 0 taken 8955775 times.
✓ Branch 1 taken 8952012 times.
17907923 for (auto &file : space->files) {
8558 8955845 int64_t old_mod_counter = file.modification_counter;
8559
8560
2/2
✓ Branch 0 taken 314 times.
✓ Branch 1 taken 8955531 times.
8955845 if (!file.is_open) {
8561 314 continue;
8562 }
8563
8564 /* Skip flushing if the file size has not changed since
8565 last flush was done and the flush mode is O_DIRECT_NO_FSYNC */
8566
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8955531 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
8955531 if (disable_flush && (file.flush_size == file.size)) {
8567 ut_ad(old_mod_counter <= file.flush_counter);
8568 continue;
8569 }
8570
8571 /* If we are here and the flush mode is O_DIRECT_NO_FSYNC, then
8572 it means that the file size has changed and hence, it should be
8573 flushed, irrespective of the mod_counter and flush counter values,
8574 which are always same in case of O_DIRECT_NO_FSYNC to avoid flush
8575 on every write operation.
8576 For other flush modes, if the flush_counter is same or ahead of
8577 the mod_counter, skip the flush. */
8578
4/4
✓ Branch 0 taken 8955524 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 9295 times.
✓ Branch 3 taken 8946229 times.
8955531 if (!disable_flush && (old_mod_counter <= file.flush_counter)) {
8579 9295 continue;
8580 }
8581
8582
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 8946233 times.
✓ Branch 2 taken 3 times.
8946236 switch (space->purpose) {
8583 case FIL_TYPE_TEMPORARY:
8584 ut_error; // we already checked for this
8585
8586 8946233 case FIL_TYPE_TABLESPACE:
8587 case FIL_TYPE_IMPORT:
8588 8946233 ++fil_n_pending_tablespace_flushes;
8589 8946233 break;
8590 }
8591
8592 8946236 bool skip_flush = is_fast_shutdown();
8593 #ifdef _WIN32
8594 if (file.is_raw_disk) {
8595 skip_flush |= true;
8596 }
8597 #endif /* _WIN32 */
8598
8599
4/4
✓ Branch 0 taken 598167 times.
✓ Branch 1 taken 8942938 times.
✓ Branch 2 taken 594882 times.
✓ Branch 3 taken 3285 times.
9541105 while (file.n_pending_flushes > 0 && !skip_flush) {
8600 /* We want to avoid calling os_file_flush() on
8601 the file twice at the same time, because we do
8602 not know what bugs OS's may contain in file
8603 I/O */
8604
8605
1/2
✓ Branch 0 taken 594882 times.
✗ Branch 1 not taken.
594882 int64_t sig_count = os_event_reset(file.sync_event);
8606
8607
1/2
✓ Branch 0 taken 594882 times.
✗ Branch 1 not taken.
594882 mutex_release();
8608
8609
1/2
✓ Branch 0 taken 594862 times.
✗ Branch 1 not taken.
594882 os_event_wait_low(file.sync_event, sig_count);
8610
8611
1/2
✓ Branch 0 taken 594882 times.
✗ Branch 1 not taken.
594862 mutex_acquire();
8612
8613
2/2
✓ Branch 0 taken 393443 times.
✓ Branch 1 taken 201439 times.
594882 if (file.flush_counter >= old_mod_counter) {
8614 393443 skip_flush |= true;
8615 }
8616 594882 skip_flush |= is_fast_shutdown();
8617 }
8618
8619
2/2
✓ Branch 0 taken 8552718 times.
✓ Branch 1 taken 393505 times.
8946223 if (!skip_flush) {
8620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8552738 times.
8552718 ut_a(file.is_open);
8621 8552738 ++file.n_pending_flushes;
8622
8623
1/2
✓ Branch 0 taken 8552809 times.
✗ Branch 1 not taken.
8552738 mutex_release();
8624
8625
1/2
✓ Branch 0 taken 8549690 times.
✗ Branch 1 not taken.
8552809 os_file_flush(file.handle);
8626
8627 8549690 file.flush_size = file.size;
8628
8629
1/2
✓ Branch 0 taken 8550992 times.
✗ Branch 1 not taken.
8549690 mutex_acquire();
8630
8631
1/2
✓ Branch 0 taken 8551898 times.
✗ Branch 1 not taken.
8550992 os_event_set(file.sync_event);
8632
8633 8551898 --file.n_pending_flushes;
8634 }
8635
8636
2/2
✓ Branch 0 taken 8552078 times.
✓ Branch 1 taken 393325 times.
8945403 if (file.flush_counter < old_mod_counter) {
8637 8552078 file.flush_counter = old_mod_counter;
8638
8639
1/2
✓ Branch 0 taken 8551940 times.
✗ Branch 1 not taken.
8552078 remove_from_unflushed_list(space);
8640 }
8641
8642
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 8945265 times.
✗ Branch 2 not taken.
8945265 switch (space->purpose) {
8643 case FIL_TYPE_TEMPORARY:
8644 ut_error; // we already checked for this
8645
8646 8945265 case FIL_TYPE_TABLESPACE:
8647 case FIL_TYPE_IMPORT:
8648 8945265 --fil_n_pending_tablespace_flushes;
8649 8945265 continue;
8650 }
8651
8652 ut_d(ut_error);
8653 }
8654
8655 8952012 --space->n_pending_flushes;
8656 }
8657
8658 147579 void fil_flush(space_id_t space_id) {
8659 147579 auto shard = fil_system->shard_by_id(space_id);
8660
8661 147579 shard->mutex_acquire();
8662
8663 /* Note: Will release and reacquire the Fil_shard::mutex. */
8664 147579 shard->space_flush(space_id);
8665
8666 147579 shard->mutex_release();
8667 147579 }
8668
8669 381894026 void Fil_shard::flush_file_spaces() {
8670
1/2
✓ Branch 0 taken 381877338 times.
✗ Branch 1 not taken.
381894026 Space_ids space_ids;
8671
8672
1/2
✓ Branch 0 taken 381911871 times.
✗ Branch 1 not taken.
381877338 mutex_acquire();
8673
8674
6/10
✓ Branch 0 taken 381909497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 381872890 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8623680 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 390508299 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8623678 times.
✓ Branch 9 taken 381884621 times.
390535555 for (auto space : m_unflushed_spaces) {
8675
4/4
✓ Branch 0 taken 8623630 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 8622539 times.
✓ Branch 3 taken 1143 times.
17247310 if ((to_int(space->purpose) & FIL_TYPE_TABLESPACE) &&
8676
2/2
✓ Branch 0 taken 8622541 times.
✓ Branch 1 taken 1089 times.
8623630 !space->stop_new_ops) {
8677
1/2
✓ Branch 0 taken 8622541 times.
✗ Branch 1 not taken.
8622539 space_ids.push_back(space->id);
8678 }
8679 }
8680
8681
1/2
✓ Branch 0 taken 382030820 times.
✗ Branch 1 not taken.
381884621 mutex_release();
8682
8683 /* Flush the spaces. It will not hurt to call fil_flush() on
8684 a non-existing space id. */
8685
2/2
✓ Branch 0 taken 8622537 times.
✓ Branch 1 taken 381927030 times.
390652651 for (auto space_id : space_ids) {
8686
1/2
✓ Branch 0 taken 8622539 times.
✗ Branch 1 not taken.
8622547 mutex_acquire();
8687
8688
1/2
✓ Branch 0 taken 8620514 times.
✗ Branch 1 not taken.
8622539 space_flush(space_id);
8689
8690
1/2
✓ Branch 0 taken 8621831 times.
✗ Branch 1 not taken.
8620514 mutex_release();
8691 }
8692 381927030 }
8693
8694 5618542 void Fil_system::flush_file_spaces() {
8695
2/2
✓ Branch 0 taken 381894600 times.
✓ Branch 1 taken 5613751 times.
387539837 for (auto shard : m_shards) {
8696
1/2
✓ Branch 0 taken 381921295 times.
✗ Branch 1 not taken.
381893079 shard->flush_file_spaces();
8697 }
8698 5613751 }
8699
8700 5604553 void fil_flush_file_spaces() { fil_system->flush_file_spaces(); }
8701
8702 /** Returns true if file address is undefined.
8703 @param[in] addr File address to check
8704 @return true if undefined */
8705 19896509 bool fil_addr_is_null(const fil_addr_t &addr) {
8706 19896509 return (addr.page == FIL_NULL);
8707 }
8708
8709 /** Get the predecessor of a file page.
8710 @param[in] page File page
8711 @return FIL_PAGE_PREV */
8712 10207500 page_no_t fil_page_get_prev(const byte *page) {
8713 10207500 return mach_read_from_4(page + FIL_PAGE_PREV);
8714 }
8715
8716 /** Get the successor of a file page.
8717 @param[in] page File page
8718 @return FIL_PAGE_NEXT */
8719 10211405 page_no_t fil_page_get_next(const byte *page) {
8720 10211405 return mach_read_from_4(page + FIL_PAGE_NEXT);
8721 }
8722
8723 /** Sets the file page type.
8724 @param[in,out] page File page
8725 @param[in] type File page type to set */
8726 3263753 void fil_page_set_type(byte *page, ulint type) {
8727 3263753 mach_write_to_2(page + FIL_PAGE_TYPE, type);
8728 3263753 }
8729
8730 /** Reset the page type.
8731 Data files created before MySQL 5.1 may contain garbage in FIL_PAGE_TYPE.
8732 In MySQL 3.23.53, only undo log pages and index pages were tagged.
8733 Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE.
8734 @param[in] page_id Page number
8735 @param[in,out] page Page with invalid FIL_PAGE_TYPE
8736 @param[in] type Expected page type
8737 @param[in,out] mtr Mini-transaction */
8738 1 void fil_page_reset_type(const page_id_t &page_id, byte *page, ulint type,
8739 mtr_t *mtr) {
8740
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 ib::info(ER_IB_MSG_334) << "Resetting invalid page " << page_id << " type "
8741
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 << fil_page_get_type(page) << " to " << type << ".";
8742 1 mlog_write_ulint(page + FIL_PAGE_TYPE, type, MLOG_2BYTES, mtr);
8743 1 }
8744
8745 /** Closes the tablespace memory cache. */
8746 8379 void fil_close() {
8747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8379 times.
8379 if (fil_system == nullptr) {
8748 return;
8749 }
8750
8751 8379 ut::delete_(fil_system);
8752
8753 8379 fil_system = nullptr;
8754 8379 fil_space_crypt_cleanup();
8755 }
8756
8757 #ifndef UNIV_HOTBACKUP
8758 /** Initializes the buffer control block used by fil_tablespace_iterate.
8759 @param[in] block Pointer to the control block
8760 @param[in] frame Pointer to buffer frame */
8761 572 static void fil_buf_block_init(buf_block_t *block, byte *frame) {
8762 UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE);
8763
8764 572 block->frame = frame;
8765
8766 572 block->page.init_io_fix();
8767 /* There are assertions that check for this. */
8768 572 block->page.buf_fix_count.store(1);
8769 572 block->page.state = BUF_BLOCK_READY_FOR_USE;
8770
8771 572 page_zip_des_init(&block->page.zip);
8772 572 }
8773
8774 struct Fil_page_iterator {
8775 /** File handle */
8776 pfs_os_file_t m_file;
8777
8778 /** File path name */
8779 const char *m_filepath;
8780
8781 /** From where to start */
8782 os_offset_t m_start;
8783
8784 /** Where to stop */
8785 os_offset_t m_end;
8786
8787 /* File size in bytes */
8788 os_offset_t m_file_size;
8789
8790 /** Page size */
8791 size_t m_page_size;
8792
8793 /** Number of pages to use for I/O */
8794 size_t m_n_io_buffers;
8795
8796 /** Buffer to use for IO */
8797 byte *m_io_buffer;
8798
8799 /** Encryption key */
8800 byte *m_encryption_key;
8801
8802 /** Encruption iv */
8803 byte *m_encryption_iv;
8804
8805 uint m_encryption_key_version;
8806 uint m_encryption_key_id;
8807 fil_space_crypt_t *m_crypt_data; /*!< Crypt data (if encrypted) */
8808
8809 /** FS Block Size */
8810 size_t block_size;
8811
8812 /** Compression algorithm to be used if the table needs to be compressed. */
8813 Compression::Type m_compression_type{};
8814 };
8815
8816 /** TODO: This can be made parallel trivially by chunking up the file
8817 and creating a callback per thread. Main benefit will be to use multiple
8818 CPUs for checksums and compressed tables. We have to do compressed tables
8819 block by block right now. Secondly we need to decompress/compress and copy
8820 too much of data. These are CPU intensive.
8821
8822 Iterate over all the pages in the tablespace.
8823 @param[in] iter Tablespace iterator
8824 @param[in,out] block Block to use for IO
8825 @param[in] callback Callback to inspect and update page contents
8826 @retval DB_SUCCESS or error code */
8827 570 static dberr_t fil_iterate(const Fil_page_iterator &iter, buf_block_t *block,
8828 PageCallback &callback) {
8829 os_offset_t offset;
8830 size_t n_bytes;
8831 570 page_no_t page_no = 0;
8832 570 space_id_t space_id = callback.get_space_id();
8833
8834 570 n_bytes = iter.m_n_io_buffers * iter.m_page_size;
8835
8836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 570 times.
570 ut_ad(!srv_read_only_mode);
8837
8838 /* For old style compressed tables we do a lot of useless copying
8839 for non-index pages. Unfortunately, it is required by
8840 buf_zip_decompress() */
8841
8842 570 ulint read_type = IORequest::READ;
8843 570 ulint write_type = IORequest::WRITE;
8844
8845
2/2
✓ Branch 0 taken 48009 times.
✓ Branch 1 taken 562 times.
48571 for (offset = iter.m_start; offset < iter.m_end; offset += n_bytes) {
8846
1/2
✓ Branch 0 taken 48009 times.
✗ Branch 1 not taken.
48009 IORequest read_request(read_type);
8847
8848 48009 byte *io_buffer = iter.m_io_buffer;
8849
8850 48009 block->frame = io_buffer;
8851
8852
2/2
✓ Branch 0 taken 3871 times.
✓ Branch 1 taken 44138 times.
48009 if (callback.get_page_size().is_compressed()) {
8853 3871 page_zip_des_init(&block->page.zip);
8854
1/2
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
3871 page_zip_set_size(&block->page.zip, iter.m_page_size);
8855
8856
1/2
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
3871 block->page.size.copy_from(
8857 page_size_t(static_cast<uint32_t>(iter.m_page_size),
8858
2/4
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3871 times.
✗ Branch 3 not taken.
3871 static_cast<uint32_t>(univ_page_size.logical()), true));
8859
8860 3871 block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
8861 3871 ut_d(block->page.zip.m_external = true);
8862
2/4
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3871 times.
3871 ut_ad(iter.m_page_size == callback.get_page_size().physical());
8863
8864 3871 read_request.mark_page_zip_compressed();
8865 3871 read_request.set_zip_page_physical_size(iter.m_page_size);
8866
8867 /* Zip IO is done in the compressed page buffer. */
8868 3871 io_buffer = block->page.zip.data;
8869 } else {
8870 44138 io_buffer = iter.m_io_buffer;
8871 }
8872
8873 /* We have to read the exact number of bytes. Otherwise the
8874 InnoDB IO functions croak on failed reads. */
8875
8876 48009 n_bytes = static_cast<ulint>(
8877 48009 std::min(static_cast<os_offset_t>(n_bytes), iter.m_end - offset));
8878
8879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48009 times.
48009 ut_ad(n_bytes > 0);
8880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48009 times.
48009 ut_ad(!(n_bytes % iter.m_page_size));
8881
8882 48009 const bool encrypted_with_keyring =
8883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48009 times.
48009 iter.m_crypt_data != NULL &&
8884 iter.m_crypt_data->type != CRYPT_SCHEME_UNENCRYPTED;
8885 dberr_t err;
8886 48009 read_request.block_size(iter.block_size);
8887
8888 /* For encrypted table, set encryption information. */
8889
8890
5/6
✓ Branch 0 taken 31021 times.
✓ Branch 1 taken 16988 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 31021 times.
✓ Branch 4 taken 16944 times.
✓ Branch 5 taken 44 times.
48009 if ((iter.m_encryption_key != NULL || encrypted_with_keyring) &&
8891 offset != 0) {
8892
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 16944 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16944 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 16944 times.
✓ Branch 6 taken 16944 times.
✗ Branch 7 not taken.
33888 read_request.encryption_key(
8893 encrypted_with_keyring ? iter.m_crypt_data->tablespace_key
8894 : iter.m_encryption_key,
8895 Encryption::KEY_LEN,
8896 encrypted_with_keyring ? iter.m_crypt_data->iv : iter.m_encryption_iv,
8897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16944 times.
16944 0, iter.m_encryption_key_id,
8898 encrypted_with_keyring ? iter.m_crypt_data->tablespace_key : nullptr,
8899 encrypted_with_keyring ? iter.m_crypt_data->uuid : nullptr, nullptr);
8900
8901
1/2
✓ Branch 0 taken 16944 times.
✗ Branch 1 not taken.
16944 read_request.encryption_algorithm(Encryption::AES);
8902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16944 times.
16944 if (iter.m_crypt_data) {
8903 read_request.encryption_rotation(
8904 iter.m_crypt_data->encryption_rotation);
8905 } else
8906
1/2
✓ Branch 0 taken 16944 times.
✗ Branch 1 not taken.
16944 read_request.encryption_rotation(Encryption_rotation::NO_ROTATION);
8907 }
8908
8909
1/2
✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
48009 err = os_file_read(read_request, iter.m_filepath, iter.m_file, io_buffer,
8910 offset, (ulint)n_bytes);
8911
8912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48007 times.
48007 if (err != DB_SUCCESS) {
8913 ib::error(ER_IB_MSG_335) << "os_file_read() failed";
8914
8915 return err;
8916 }
8917
8918 size_t n_pages_read;
8919 48007 bool updated = false;
8920 48007 os_offset_t page_off = offset;
8921
8922 48007 n_pages_read = (ulint)n_bytes / iter.m_page_size;
8923
8924
2/2
✓ Branch 0 taken 48007 times.
✓ Branch 1 taken 48001 times.
96008 for (size_t i = 0; i < n_pages_read; ++i) {
8925
1/2
✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
48007 buf_block_set_file_page(block, page_id_t(space_id, page_no++));
8926
8927 /* We are going to modify the page. Add to page tracking system. */
8928
1/2
✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
48007 arch_page_sys->track_page(&block->page, LSN_MAX, LSN_MAX, true);
8929
8930
3/4
✓ Branch 0 taken 48007 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 48001 times.
48007 if ((err = callback(page_off, block)) != DB_SUCCESS) {
8931 6 return err;
8932
8933
1/2
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
48001 } else if (!updated) {
8934
1/2
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
48001 updated = buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE;
8935 }
8936
8937
1/2
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
48001 buf_block_set_state(block, BUF_BLOCK_NOT_USED);
8938
1/2
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
48001 buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
8939
8940 48001 page_off += iter.m_page_size;
8941 48001 block->frame += iter.m_page_size;
8942 }
8943
8944
1/2
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
48001 IORequest write_request(write_type);
8945 48001 write_request.block_size(iter.block_size);
8946
8947 /* For encrypted table, set encryption information. */
8948
4/4
✓ Branch 0 taken 16986 times.
✓ Branch 1 taken 31015 times.
✓ Branch 2 taken 16942 times.
✓ Branch 3 taken 44 times.
48001 if (iter.m_encryption_key != NULL && offset != 0 &&
8949
1/2
✓ Branch 0 taken 16942 times.
✗ Branch 1 not taken.
16942 iter.m_crypt_data == NULL) {
8950 16942 write_request.encryption_key(
8951 16942 iter.m_encryption_key, Encryption::KEY_LEN, iter.m_encryption_iv,
8952
1/2
✓ Branch 0 taken 16942 times.
✗ Branch 1 not taken.
16942 iter.m_encryption_key_version, iter.m_encryption_key_id, nullptr,
8953 nullptr, nullptr);
8954
1/2
✓ Branch 0 taken 16942 times.
✗ Branch 1 not taken.
16942 write_request.encryption_algorithm(Encryption::AES);
8955
3/4
✓ Branch 0 taken 30492 times.
✓ Branch 1 taken 567 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30492 times.
31059 } else if (offset != 0 && iter.m_crypt_data) {
8956 write_request.encryption_key(
8957 iter.m_encryption_key, Encryption::KEY_LEN, iter.m_encryption_iv,
8958 iter.m_encryption_key_version, iter.m_crypt_data->key_id, nullptr,
8959 iter.m_crypt_data->uuid, nullptr);
8960
8961 write_request.encryption_algorithm(Encryption::KEYRING);
8962
8963 if (callback.get_page_size().is_compressed()) {
8964 write_request.mark_page_zip_compressed();
8965 write_request.set_zip_page_physical_size(iter.m_page_size);
8966 }
8967 }
8968
8969 /* For compressed table, set compressed information.
8970 @note os_file_compress_page() function expects that the page size is a
8971 multiple of OS punch hole size so we make sure it's true before turning
8972 on compression. */
8973 97282 if (iter.m_compression_type != Compression::Type::NONE &&
8974
6/8
✓ Branch 0 taken 1280 times.
✓ Branch 1 taken 46721 times.
✓ Branch 2 taken 1280 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1280 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1280 times.
✓ Branch 7 taken 46721 times.
49281 IORequest::is_punch_hole_supported() &&
8975
1/2
✓ Branch 0 taken 1280 times.
✗ Branch 1 not taken.
1280 !(srv_page_size % iter.block_size)) {
8976
1/2
✓ Branch 0 taken 1280 times.
✗ Branch 1 not taken.
1280 write_request.compression_algorithm(iter.m_compression_type);
8977
8978 /* In the case of import since we're doing compression for the first time
8979 we would like to ignore any optimisations to not do punch hole. So force
8980 the punch hole. */
8981
1/2
✓ Branch 0 taken 1280 times.
✗ Branch 1 not taken.
1280 write_request.disable_punch_hole_optimisation();
8982 }
8983
8984 /* A page was updated in the set, write back to disk. */
8985
8986
4/8
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48001 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 48001 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48001 times.
48001 if (updated && (err = os_file_write(write_request, iter.m_filepath,
8987 iter.m_file, io_buffer, offset,
8988 (ulint)n_bytes)) != DB_SUCCESS) {
8989 /* This is not a hard error */
8990 if (err == DB_IO_NO_PUNCH_HOLE) {
8991 err = DB_SUCCESS;
8992 write_type &= ~IORequest::PUNCH_HOLE;
8993
8994 } else {
8995 ib::error(ER_IB_MSG_336) << "os_file_write() failed";
8996
8997 return err;
8998 }
8999 }
9000
3/4
✓ Branch 0 taken 48001 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48001 times.
✓ Branch 3 taken 6 times.
48007 }
9001
9002 562 return DB_SUCCESS;
9003 }
9004
9005 1294 void fil_adjust_name_import(dict_table_t *table [[maybe_unused]],
9006 const char *path,
9007 ib_file_suffix extn [[maybe_unused]]) {
9008 /* Try to open with current name first. */
9009
3/4
✓ Branch 0 taken 1294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1225 times.
✓ Branch 3 taken 69 times.
1294 if (os_file_exists(path)) {
9010 1225 return;
9011 }
9012
9013 /* On failure we need to check if file exists in different letter case
9014 for partitioned table. */
9015
9016 /* Safe check. Never needed on Windows. */
9017 #ifndef _WIN32
9018 /* Needed only for case sensitive file system. */
9019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 if (lower_case_file_system) {
9020 return;
9021 }
9022
9023 /* Only needed for partition file. */
9024
4/6
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 42 times.
69 if (!dict_name::is_partition(table->name.m_name)) {
9025 27 return;
9026 }
9027
9028 /* Get Import directory path. */
9029
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 std::string import_dir(path);
9030 42 Fil_path::normalize(import_dir);
9031
9032 42 auto pos = import_dir.find_last_of(Fil_path::SEPARATOR);
9033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (pos == std::string::npos) {
9034 import_dir.assign(Fil_path::DOT_SLASH);
9035
9036 } else {
9037
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 import_dir.resize(pos + 1);
9038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 ut_ad(Fil_path::is_separator(import_dir.back()));
9039 }
9040
9041 /* Walk through all files under the directory and match the import file
9042 after adjusting case. This is a safe check to allow files exported from
9043 earlier versions where the case for partition name and separator could
9044 be different. */
9045 42 bool found_path = false;
9046 42 std::string saved_path;
9047
9048
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 Dir_Walker::walk(import_dir, false, [&](const std::string &file_path) {
9049 /* Skip entry if already found. */
9050
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 267 times.
549 if (found_path) {
9051 519 return;
9052 }
9053 /* Check only for partition files. */
9054
3/4
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 259 times.
267 if (!dict_name::is_partition(file_path)) {
9055 8 return;
9056 }
9057
9058 /* Extract table name from path. */
9059 259 std::string table_name;
9060
3/4
✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
✓ Branch 3 taken 111 times.
259 if (!Fil_path::parse_file_path(file_path, extn, table_name)) {
9061 /* Not a valid file-per-table path */
9062 148 return;
9063 }
9064
9065 /* Check if the file name would match after correcting the case. */
9066
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 dict_name::rebuild(table_name);
9067
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 30 times.
111 if (table_name.compare(table->name.m_name) != 0) {
9068 81 return;
9069 }
9070
9071
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 saved_path.assign(file_path);
9072 30 found_path = true;
9073
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 229 times.
259 });
9074
9075 /* Check and rename the import file name. */
9076
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
42 if (found_path) {
9077
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 fil_rename_partition_file(saved_path, extn, false, true);
9078 }
9079 #endif /* !WIN32 */
9080
9081 42 return;
9082 42 }
9083
9084 584 dberr_t fil_tablespace_iterate(dict_table_t *table, ulint n_io_buffers,
9085 Compression::Type compression_type,
9086 PageCallback &callback) {
9087 dberr_t err;
9088 pfs_os_file_t file;
9089 char *filepath;
9090 bool success;
9091
9092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
584 ut_a(n_io_buffers > 0);
9093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
584 ut_ad(!srv_read_only_mode);
9094
9095
3/4
✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 582 times.
584 DBUG_EXECUTE_IF("ib_import_trigger_corruption_1", return DB_CORRUPTION;);
9096
9097 /* Make sure the data_dir_path is set. */
9098
1/2
✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
582 dd_get_and_save_data_dir_path<dd::Table>(table, nullptr, false);
9099
9100
1/2
✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
582 std::string path = dict_table_get_datadir(table);
9101
9102
2/4
✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 582 times.
✗ Branch 3 not taken.
582 filepath = Fil_path::make(path, table->name.m_name, IBD, true);
9103
9104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 582 times.
582 if (filepath == nullptr) {
9105 return DB_OUT_OF_MEMORY;
9106 }
9107
9108 /* Adjust filename for partition file if in different letter case. */
9109
1/2
✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
582 fil_adjust_name_import(table, filepath, IBD);
9110
9111
1/2
✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
582 file = os_file_create_simple_no_error_handling(
9112 innodb_data_file_key, filepath, OS_FILE_OPEN, OS_FILE_READ_WRITE,
9113 srv_read_only_mode, &success);
9114
9115
2/14
✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 582 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
582 DBUG_EXECUTE_IF("fil_tablespace_iterate_failure", {
9116 static bool once;
9117
9118 if (!once || ut::random_from_interval(0, 10) == 5) {
9119 once = true;
9120 success = false;
9121 os_file_close(file);
9122 }
9123 });
9124
9125
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 572 times.
582 if (!success) {
9126 /* The following call prints an error message */
9127
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 os_file_get_last_error(true);
9128
9129
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
20 ib::error(ER_IB_MSG_337) << "Trying to import a tablespace, but could not"
9130
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 " open the tablespace file "
9131
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 << filepath;
9132
9133 10 ut::free(filepath);
9134
9135 10 return DB_TABLESPACE_NOT_FOUND;
9136
9137 } else {
9138 572 err = DB_SUCCESS;
9139 }
9140
9141 /* Set File System Block Size */
9142 size_t block_size;
9143 {
9144 os_file_stat_t stat_info;
9145
9146
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 ut_d(dberr_t err =) os_file_get_status(filepath, &stat_info, false, false);
9147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
572 ut_ad(err == DB_SUCCESS);
9148
9149 572 block_size = stat_info.block_size;
9150 }
9151
9152 572 callback.set_file(filepath, file);
9153
9154
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 os_offset_t file_size = os_file_get_size(file);
9155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
572 ut_a(file_size != (os_offset_t)-1);
9156
9157 /* The block we will use for every physical page */
9158 buf_block_t *block;
9159
9160 block = reinterpret_cast<buf_block_t *>(
9161 572 ut::zalloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, sizeof(*block)));
9162
9163
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 mutex_create(LATCH_ID_BUF_BLOCK_MUTEX, &block->mutex);
9164
9165 /* Allocate a page to read in the tablespace header, so that we
9166 can determine the page size and zip size (if it is compressed).
9167 We allocate an extra page in case it is a compressed table. One
9168 page is to ensure alignment. */
9169
9170 byte *page = static_cast<byte *>(
9171 572 ut::aligned_alloc(2 * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
9172
9173 572 fil_buf_block_init(block, page);
9174
9175 /* Read the first page and determine the page and zip size. */
9176
9177
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 IORequest request(IORequest::READ);
9178
9179
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 err = os_file_read_first_page(request, path.c_str(), file, page,
9180 UNIV_PAGE_SIZE);
9181
9182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
572 if (err != DB_SUCCESS) {
9183 err = DB_IO_ERROR;
9184
9185
2/4
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 572 times.
✗ Branch 3 not taken.
572 } else if ((err = callback.init(file_size, block)) == DB_SUCCESS) {
9186 572 Fil_page_iterator iter;
9187
9188 572 iter.m_file = file;
9189 572 iter.m_start = 0;
9190 572 iter.m_end = file_size;
9191 572 iter.m_filepath = filepath;
9192 572 iter.m_file_size = file_size;
9193 572 iter.m_n_io_buffers = n_io_buffers;
9194
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 iter.m_page_size = callback.get_page_size().physical();
9195 572 iter.block_size = block_size;
9196
9197 572 iter.m_compression_type = compression_type;
9198
9199 /* Check encryption is matched or not. */
9200
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 ulint space_flags = callback.get_space_flags();
9201 572 iter.m_crypt_data =
9202
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 fil_space_read_crypt_data(callback.get_page_size(), page);
9203
9204 /* read (optional) crypt data */
9205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 572 times.
572 if (iter.m_crypt_data &&
9206 iter.m_crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) {
9207 ut_ad(FSP_FLAGS_GET_ENCRYPTION(space_flags));
9208 iter.m_encryption_key_id = iter.m_crypt_data->key_id;
9209
9210 Encryption::get_latest_tablespace_key(
9211 iter.m_crypt_data->key_id, iter.m_crypt_data->uuid,
9212 &iter.m_encryption_key_version, &iter.m_encryption_key);
9213 if (iter.m_encryption_key == NULL) err = DB_IO_DECRYPT_FAIL;
9214 } else {
9215 /* Set encryption info. */
9216 572 iter.m_encryption_key = table->encryption_key;
9217 572 iter.m_encryption_iv = table->encryption_iv;
9218 572 iter.m_encryption_key_version = ~0; // TODO:Robert:flipping bits so to
9219 // make this a marker that tablespace
9220 // key id used
9221 }
9222
9223 /* Check encryption is matched or not. */
9224
5/6
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 526 times.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 526 times.
572 if (err == DB_SUCCESS && FSP_FLAGS_GET_ENCRYPTION(space_flags)) {
9225
3/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 44 times.
46 if (!dd_is_table_in_encrypted_tablespace(table)) {
9226
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 ib::error(ER_IB_MSG_338) << "Table is not in an encrypted tablespace,"
9227 " but the data file intended for import"
9228
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 " is an encrypted tablespace";
9229
9230 2 err = DB_IO_NO_ENCRYPT_TABLESPACE;
9231 } else {
9232 /* encryption_key must have been populated while reading CFP file. */
9233
3/6
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
44 ut_ad(table->encryption_key != nullptr &&
9234 table->encryption_iv != nullptr);
9235
9236
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 if (table->encryption_key == nullptr ||
9237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 table->encryption_iv == nullptr) {
9238 err = DB_ERROR;
9239 }
9240 }
9241 }
9242
9243
2/2
✓ Branch 0 taken 570 times.
✓ Branch 1 taken 2 times.
572 if (err == DB_SUCCESS) {
9244 /* Compressed pages can't be optimised for block IO
9245 for now. We do the IMPORT page by page. */
9246
9247
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 545 times.
570 if (callback.get_page_size().is_compressed()) {
9248 25 iter.m_n_io_buffers = 1;
9249
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
25 ut_a(iter.m_page_size == callback.get_page_size().physical());
9250 }
9251
9252 /** Add an extra page for compressed page scratch
9253 area. */
9254 1140 iter.m_io_buffer = static_cast<byte *>(ut::aligned_alloc(
9255 570 (1 + iter.m_n_io_buffers) * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
9256
9257
1/2
✓ Branch 0 taken 568 times.
✗ Branch 1 not taken.
570 err = fil_iterate(iter, block, callback);
9258
9259 568 ut::aligned_free(iter.m_io_buffer);
9260 }
9261
9262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 570 times.
570 if (iter.m_crypt_data) {
9263 fil_space_destroy_crypt_data(&iter.m_crypt_data);
9264 if (iter.m_encryption_key != NULL) my_free(iter.m_encryption_key);
9265 }
9266 }
9267
9268
2/2
✓ Branch 0 taken 562 times.
✓ Branch 1 taken 8 times.
570 if (err == DB_SUCCESS) {
9269
2/4
✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 562 times.
✗ Branch 3 not taken.
562 ib::info(ER_IB_MSG_339) << "Sync to disk";
9270
9271
2/4
✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 562 times.
562 if (!os_file_flush(file)) {
9272 ib::info(ER_IB_MSG_340) << "os_file_flush() failed!";
9273 err = DB_IO_ERROR;
9274 } else {
9275
2/4
✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 562 times.
✗ Branch 3 not taken.
562 ib::info(ER_IB_MSG_341) << "Sync to disk - done!";
9276 }
9277 }
9278
9279
1/2
✓ Branch 0 taken 570 times.
✗ Branch 1 not taken.
570 os_file_close(file);
9280
9281 570 ut::aligned_free(page);
9282 570 ut::free(filepath);
9283
9284
1/2
✓ Branch 0 taken 570 times.
✗ Branch 1 not taken.
570 mutex_free(&block->mutex);
9285
9286 570 ut::free(block);
9287
9288 570 return err;
9289 580 }
9290 #endif /* !UNIV_HOTBACKUP */
9291
9292 /** Set the tablespace table size.
9293 @param[in] page a page belonging to the tablespace */
9294 572 void PageCallback::set_page_size(const buf_frame_t *page) UNIV_NOTHROW {
9295
1/2
✓ Branch 0 taken 572 times.
✗ Branch 1 not taken.
572 m_page_size.copy_from(fsp_header_get_page_size(page));
9296 572 }
9297
9298 /** Delete the tablespace file and any related files like .cfg.
9299 This should not be called for temporary tables.
9300 @param[in] path File path of the IBD tablespace
9301 @return true on success */
9302 197 bool fil_delete_file(const char *path) {
9303 197 bool success = true;
9304
9305 /* Force a delete of any stale .ibd files that are lying around. */
9306 197 success = os_file_delete_if_exists(innodb_data_file_key, path, nullptr);
9307
9308
2/4
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197 times.
✗ Branch 3 not taken.
197 char *cfg_filepath = Fil_path::make_cfg(path);
9309
9310
1/2
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
197 if (cfg_filepath != nullptr) {
9311 197 os_file_delete_if_exists(innodb_data_file_key, cfg_filepath, nullptr);
9312
9313 197 ut::free(cfg_filepath);
9314 }
9315
9316
2/4
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197 times.
✗ Branch 3 not taken.
197 char *cfp_filepath = Fil_path::make_cfp(path);
9317
9318
1/2
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
197 if (cfp_filepath != nullptr) {
9319 197 os_file_delete_if_exists(innodb_data_file_key, cfp_filepath, nullptr);
9320
9321 197 ut::free(cfp_filepath);
9322 }
9323
9324 197 return success;
9325 }
9326
9327 #ifndef UNIV_HOTBACKUP
9328 35694 dberr_t fil_rename_precheck(const dict_table_t *old_table,
9329 const dict_table_t *new_table,
9330 const char *tmp_name) {
9331
1/2
✓ Branch 0 taken 35694 times.
✗ Branch 1 not taken.
35694 bool old_is_file_per_table = dict_table_is_file_per_table(old_table);
9332
1/2
✓ Branch 0 taken 35694 times.
✗ Branch 1 not taken.
35694 bool new_is_file_per_table = dict_table_is_file_per_table(new_table);
9333
9334 /* If neither table is file-per-table, there will be no renaming of files. */
9335
4/4
✓ Branch 0 taken 13235 times.
✓ Branch 1 taken 22459 times.
✓ Branch 2 taken 13129 times.
✓ Branch 3 taken 106 times.
35694 if (!old_is_file_per_table && !new_is_file_per_table) {
9336 13129 return DB_SUCCESS;
9337 }
9338
9339 43585 auto fetch_path = [](std::string &path, const dict_table_t *source_table,
9340 bool fpt) -> dberr_t {
9341 43585 char *path_ptr{};
9342
9343 /* It is possible that the file could be present in a directory outside of
9344 the data directory (possible because of innodb_directories option), so
9345 fetch the path accordingly.
9346
9347 We are only interested in fetching the right path for file-per-table
9348 tablespaces as during file_rename_tablespace_check the source table should
9349 always exist and we do the rename for only source tables which are
9350 file-per-table tablspaces. */
9351
6/6
✓ Branch 0 taken 43479 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 43471 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 43471 times.
✓ Branch 5 taken 114 times.
43585 if (fpt && !dict_table_is_discarded(source_table)) {
9352 43471 path_ptr = fil_space_get_first_path(source_table->space);
9353
9354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43471 times.
43471 if (path_ptr == nullptr) {
9355 return DB_TABLESPACE_NOT_FOUND;
9356 }
9357 } else {
9358
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 auto dir = dict_table_get_datadir(source_table);
9359
9360 path_ptr =
9361
2/4
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
114 Fil_path::make(dir, source_table->name.m_name, IBD, !dir.empty());
9362
9363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 if (path_ptr == nullptr) {
9364 return DB_OUT_OF_MEMORY;
9365 }
9366
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 }
9367
9368 43585 path.assign(path_ptr);
9369 43585 ut::free(path_ptr);
9370
9371 43585 return DB_SUCCESS;
9372 };
9373
9374 22565 std::string old_path;
9375
9376
1/2
✓ Branch 0 taken 22565 times.
✗ Branch 1 not taken.
22565 auto err = fetch_path(old_path, old_table, old_is_file_per_table);
9377
9378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22565 times.
22565 if (err != DB_SUCCESS) {
9379 return err;
9380 }
9381
9382
2/2
✓ Branch 0 taken 22459 times.
✓ Branch 1 taken 106 times.
22565 if (old_is_file_per_table) {
9383 std::string tmp_path =
9384
3/6
✓ Branch 0 taken 22459 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22459 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22459 times.
✗ Branch 5 not taken.
44918 Fil_path::make_new_path(old_path.c_str(), tmp_name, IBD);
9385
9386 /* Temp filepath must not exist. */
9387
1/2
✓ Branch 0 taken 22459 times.
✗ Branch 1 not taken.
22459 err = fil_rename_tablespace_check(old_table->space, old_path.c_str(),
9388 tmp_path.c_str(),
9389 22459 dict_table_is_discarded(old_table));
9390
9391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22459 times.
22459 if (err != DB_SUCCESS) {
9392 return err;
9393 }
9394
1/2
✓ Branch 0 taken 22459 times.
✗ Branch 1 not taken.
22459 }
9395
9396
2/2
✓ Branch 0 taken 21020 times.
✓ Branch 1 taken 1545 times.
22565 if (new_is_file_per_table) {
9397 21020 std::string new_path;
9398
9399
1/2
✓ Branch 0 taken 21020 times.
✗ Branch 1 not taken.
21020 err = fetch_path(new_path, new_table, new_is_file_per_table);
9400
9401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21020 times.
21020 if (err != DB_SUCCESS) {
9402 return err;
9403 }
9404
9405 /* Destination filepath must not exist unless this ALTER TABLE starts and
9406 ends with a file_per-table tablespace. */
9407
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 20914 times.
21020 if (!old_is_file_per_table) {
9408
1/2
✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
106 err = fil_rename_tablespace_check(new_table->space, new_path.c_str(),
9409 old_path.c_str(),
9410 106 dict_table_is_discarded(new_table));
9411 }
9412
1/2
✓ Branch 0 taken 21020 times.
✗ Branch 1 not taken.
21020 }
9413
9414 22565 return err;
9415 22565 }
9416 #endif /* !UNIV_HOTBACKUP */
9417
9418 /** Note that the file system where the file resides doesn't support PUNCH HOLE.
9419 Called from AIO handlers when IO returns DB_IO_NO_PUNCH_HOLE
9420 @param[in,out] file file to set */
9421 1247 void fil_no_punch_hole(fil_node_t *file) { file->punch_hole = false; }
9422
9423 546922 dberr_t fil_set_compression(space_id_t space_id, const char *algorithm) {
9424 dberr_t err;
9425 546922 Compression compression;
9426
9427
3/4
✓ Branch 0 taken 451 times.
✓ Branch 1 taken 546473 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 451 times.
546924 if (algorithm == nullptr || strlen(algorithm) == 0) {
9428 #ifndef UNIV_DEBUG
9429 compression.m_type = Compression::NONE;
9430 #else /* UNIV_DEBUG */
9431 /* This is a Debug tool for setting compression on all
9432 compressible tables not otherwise specified. */
9433
1/2
✓ Branch 0 taken 546473 times.
✗ Branch 1 not taken.
546473 switch (srv_debug_compress) {
9434 546473 case Compression::LZ4:
9435 case Compression::ZLIB:
9436 case Compression::NONE:
9437
9438 546473 compression.m_type = static_cast<Compression::Type>(srv_debug_compress);
9439 546473 break;
9440
9441 default:
9442 compression.m_type = Compression::NONE;
9443 }
9444
9445 #endif /* UNIV_DEBUG */
9446
9447 546473 err = DB_SUCCESS;
9448
9449 } else {
9450
1/2
✓ Branch 0 taken 451 times.
✗ Branch 1 not taken.
451 err = Compression::check(algorithm, &compression);
9451 }
9452
9453
1/2
✓ Branch 0 taken 546923 times.
✗ Branch 1 not taken.
546924 fil_space_t *space = fil_space_get(space_id);
9454
9455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 546923 times.
546923 if (space == nullptr) {
9456 return DB_NOT_FOUND;
9457 }
9458
9459
1/2
✓ Branch 0 taken 546924 times.
✗ Branch 1 not taken.
546923 const page_size_t page_size(space->flags);
9460
9461
1/2
✓ Branch 0 taken 546923 times.
✗ Branch 1 not taken.
546924 if (!fsp_is_file_per_table(space_id, space->flags) ||
9462
6/10
✓ Branch 0 taken 546923 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 546923 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 546924 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 546922 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 546922 times.
546923 fsp_is_system_temporary(space_id) || page_size.is_compressed()) {
9463 return DB_IO_NO_PUNCH_HOLE_TABLESPACE;
9464 }
9465
9466 546922 space->compression_type = compression.m_type;
9467
9468
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 546614 times.
546922 if (space->compression_type != Compression::NONE) {
9469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
308 if (!space->files.front().punch_hole) {
9470 return DB_IO_NO_PUNCH_HOLE_FS;
9471 }
9472 }
9473
9474 546922 return err;
9475 }
9476
9477 /** Get the compression algorithm for a tablespace.
9478 @param[in] space_id Space ID to check
9479 @return the compression algorithm */
9480 642 Compression::Type fil_get_compression(space_id_t space_id) {
9481 642 fil_space_t *space = fil_space_get(space_id);
9482
9483
1/2
✓ Branch 0 taken 642 times.
✗ Branch 1 not taken.
642 return space == nullptr ? Compression::NONE : space->compression_type;
9484 }
9485
9486 /** Set the autoextend_size attribute for the tablespace
9487 @param[in] space_id Space ID of tablespace for which to set
9488 @param[in] autoextend_size Value of autoextend_size attribute
9489 @return DB_SUCCESS or error code */
9490 323910 dberr_t fil_set_autoextend_size(space_id_t space_id, uint64_t autoextend_size) {
9491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 323910 times.
323910 ut_ad(space_id != TRX_SYS_SPACE);
9492
9493 323910 fil_space_t *space = fil_space_acquire(space_id);
9494
9495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 323910 times.
323910 if (space == nullptr) {
9496 return DB_NOT_FOUND;
9497 }
9498
9499 323910 rw_lock_x_lock(&space->latch, UT_LOCATION_HERE);
9500
9501 323910 space->autoextend_size_in_bytes = autoextend_size;
9502
9503 323910 rw_lock_x_unlock(&space->latch);
9504
9505 323910 fil_space_release(space);
9506
9507 323910 return DB_SUCCESS;
9508 }
9509
9510 /** Set the encryption type for the tablespace
9511 @param[in] space_id Space ID of tablespace for which to set
9512 @param[in] algorithm Encryption algorithm
9513 @param[in] key Encryption key
9514 @param[in] iv Encryption iv
9515 @param[in] acquire_mutex if true acquire fil_sys mutex, else false
9516 @return DB_SUCCESS or error code */
9517 2749 dberr_t fil_set_encryption(space_id_t space_id, Encryption::Type algorithm,
9518 byte *key, byte *iv, bool acquire_mutex) {
9519 2749 auto shard = fil_system->shard_by_id(space_id);
9520
9521
1/2
✓ Branch 0 taken 2749 times.
✗ Branch 1 not taken.
2749 if (acquire_mutex) shard->mutex_acquire();
9522
9523 2749 fil_space_t *space = shard->get_space_by_id(space_id);
9524
9525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2749 times.
2749 if (space == nullptr) {
9526 if (acquire_mutex) {
9527 shard->mutex_release();
9528 }
9529 return DB_NOT_FOUND;
9530 }
9531
9532 2749 Encryption::set_or_generate(algorithm, key, iv, space->m_encryption_metadata);
9533
9534
2/2
✓ Branch 0 taken 2733 times.
✓ Branch 1 taken 16 times.
2749 if (space->crypt_data == nullptr) fsp_flags_set_encryption(space->flags);
9535
9536
1/2
✓ Branch 0 taken 2749 times.
✗ Branch 1 not taken.
2749 if (acquire_mutex) {
9537 2749 shard->mutex_release();
9538 }
9539
9540 2749 return DB_SUCCESS;
9541 }
9542
9543 /** Enable encryption of temporary tablespace
9544 @param[in,out] space tablespace object
9545 @return DB_SUCCESS on success, DB_ERROR on failure */
9546 41 dberr_t fil_temp_update_encryption(fil_space_t *space) {
9547 /* Make sure the keyring is loaded. */
9548
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 38 times.
41 if (!Encryption::check_keyring()) {
9549
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 ib::error() << "Can't set temporary tablespace"
9550
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 << " to be encrypted because"
9551
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 << " keyring plugin is not"
9552
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 << " available.";
9553 3 return (DB_ERROR);
9554 }
9555
9556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (!fsp_enable_encryption(space)) {
9557 ib::error() << "Can't set temporary tablespace"
9558 << " to be encrypted.";
9559 return (DB_ERROR);
9560 }
9561
9562 const dberr_t err =
9563 38 fil_set_encryption(space->id, Encryption::AES, nullptr, nullptr);
9564
9565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 ut_ad(err == DB_SUCCESS);
9566
9567 38 return (err);
9568 }
9569
9570 /** Reset the encryption type for the tablespace
9571 @param[in] space_id Space ID of tablespace for which to set
9572 @return DB_SUCCESS or error code */
9573 139 dberr_t fil_reset_encryption(space_id_t space_id) {
9574
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 ut_ad(space_id != TRX_SYS_SPACE);
9575
9576 139 auto shard = fil_system->shard_by_id(space_id);
9577
9578 139 shard->mutex_acquire();
9579
9580 139 fil_space_t *space = shard->get_space_by_id(space_id);
9581
9582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 if (space == nullptr) {
9583 shard->mutex_release();
9584 return DB_NOT_FOUND;
9585 }
9586
9587 139 space->m_encryption_metadata = {};
9588
9589 139 shard->mutex_release();
9590
9591 139 return DB_SUCCESS;
9592 }
9593
9594 #ifndef UNIV_HOTBACKUP
9595 256423 bool Fil_shard::needs_encryption_rotate(fil_space_t *space) {
9596 /* We only rotate if encryption is already set. */
9597
2/2
✓ Branch 0 taken 207346 times.
✓ Branch 1 taken 49077 times.
256423 if (!space->can_encrypt()) {
9598 207346 return false;
9599 }
9600
9601 /* Deleted spaces do not need rotation. Their pages are being
9602 deleted from the buffer pool. */
9603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49077 times.
49077 if (space->is_deleted()) {
9604 return false;
9605 }
9606
9607 /* Skip unencypted tablespaces. */
9608
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 49050 times.
49077 if (fsp_is_system_or_temp_tablespace(space->id)) {
9609 27 return false;
9610 }
9611
9612
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 49046 times.
49050 DBUG_EXECUTE_IF(
9613 "ib_encryption_rotate_skip",
9614 ib::info(ER_IB_MSG_INJECT_FAILURE, "ib_encryption_rotate_skip");
9615 return false;);
9616
9617 49046 return true;
9618 }
9619
9620 716044 size_t Fil_shard::encryption_rotate(size_t *rotate_count) {
9621 /* If there are no tablespaces to rotate, return true. */
9622 716044 size_t fail_count = 0;
9623 byte encrypt_info[Encryption::INFO_SIZE];
9624 using Spaces_to_rotate = std::vector<fil_space_t *>;
9625 716044 Spaces_to_rotate spaces2rotate;
9626
9627 /* Use the shard mutex to collect a list of the spaces to rotate. */
9628
1/2
✓ Branch 0 taken 716044 times.
✗ Branch 1 not taken.
716044 mutex_acquire();
9629
9630
2/2
✓ Branch 0 taken 256423 times.
✓ Branch 1 taken 716044 times.
972467 for (auto &elem : m_spaces) {
9631 256423 auto space = elem.second;
9632
9633
3/4
✓ Branch 0 taken 256423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 207377 times.
✓ Branch 3 taken 49046 times.
256423 if (!needs_encryption_rotate(space)) {
9634 207377 continue;
9635 }
9636
9637 /* Skip the temporary tablespace when it's in default key status,
9638 since it's the first server startup after bootstrap, and the
9639 server uuid is not ready yet. */
9640
3/6
✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 49046 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 49046 times.
49046 if (fsp_is_system_temporary(space->id) &&
9641 Encryption::get_master_key_id() == Encryption::DEFAULT_MASTER_KEY_ID)
9642 continue;
9643
9644
1/2
✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
49046 spaces2rotate.push_back(space);
9645 }
9646
9647
1/2
✓ Branch 0 taken 716044 times.
✗ Branch 1 not taken.
716044 mutex_release();
9648
9649 /* We can now be assured that each fil_space_t collected above will not be
9650 deleted below (outside the shard mutex protection) because:
9651 1. The caller, Rotate_innodb_master_key::execute(), holds an exclusive
9652 backup lock which blocks any other concurrent DDL or MDL on this space.
9653 2. Only a thread with an MDL on the space name can mark a fil_space_t as
9654 deleted or actually delete it. This includes background threads like
9655 the purge thread doing undo truncation as well as any client DDL.
9656 3. We assured above using the shard mutex that the space is not deleted. */
9657
9658
2/2
✓ Branch 0 taken 49046 times.
✓ Branch 1 taken 716044 times.
765090 for (auto &space : spaces2rotate) {
9659 /* Rotate this encrypted tablespace. */
9660
1/2
✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
49046 mtr_t mtr;
9661
1/2
✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
49046 mtr_start(&mtr);
9662 49046 memset(encrypt_info, 0, Encryption::INFO_SIZE);
9663
1/2
✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
49046 bool rotate_ok = fsp_header_rotate_encryption(space, encrypt_info, &mtr);
9664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49046 times.
49046 ut_ad(rotate_ok);
9665
1/2
✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
49046 mtr_commit(&mtr);
9666
9667
1/2
✓ Branch 0 taken 49046 times.
✗ Branch 1 not taken.
49046 if (rotate_ok) {
9668 49046 ++(*rotate_count);
9669 } else {
9670 ++fail_count;
9671 }
9672 49046 }
9673
9674 /* This crash forces encryption rotate to complete at startup. */
9675
5/8
✓ Branch 0 taken 716044 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 716040 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
716044 DBUG_EXECUTE_IF(
9676 "ib_encryption_rotate_crash",
9677 ib::info(ER_IB_MSG_INJECT_FAILURE, "ib_encryption_rotate_crash");
9678 DBUG_SUICIDE(););
9679
9680 716040 return fail_count;
9681 716040 }
9682
9683 10534 size_t Fil_system::encryption_rotate() {
9684 10534 size_t fail_count = 0;
9685 10534 size_t rotate_count = 0;
9686
9687
2/2
✓ Branch 0 taken 716044 times.
✓ Branch 1 taken 10530 times.
726574 for (auto shard : m_shards) {
9688
1/2
✓ Branch 0 taken 716040 times.
✗ Branch 1 not taken.
716044 fail_count += shard->encryption_rotate(&rotate_count);
9689 }
9690
9691
2/2
✓ Branch 0 taken 1309 times.
✓ Branch 1 taken 9221 times.
10530 if (rotate_count > 0) {
9692
1/2
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
1309 ib::info(ER_IB_MSG_MASTER_KEY_ROTATED, static_cast<int>(rotate_count));
9693 }
9694
9695 10530 return fail_count;
9696 }
9697
9698 9331 void Fil_system::encryption_reencrypt(
9699 std::vector<space_id_t> &space_id_vector) {
9700 /* If there are no tablespaces to reencrypt, return true. */
9701
1/2
✓ Branch 0 taken 9331 times.
✗ Branch 1 not taken.
9331 if (space_id_vector.empty()) {
9702 9331 return;
9703 }
9704
9705 size_t fail_count = 0;
9706 size_t rotate_count = 0;
9707 byte encrypt_info[Encryption::INFO_SIZE];
9708
9709 /* This operation is done either post recovery or when the first time
9710 tablespace is loaded. */
9711
9712 for (auto &space_id : space_id_vector) {
9713 fil_space_t *space = fil_space_get(space_id);
9714 ut_ad(space != nullptr);
9715 ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags));
9716
9717 /* Rotate this encrypted tablespace. */
9718 mtr_t mtr;
9719 mtr_start(&mtr);
9720 memset(encrypt_info, 0, Encryption::INFO_SIZE);
9721 bool rotate_ok = fsp_header_rotate_encryption(space, encrypt_info, &mtr);
9722 ut_ad(rotate_ok);
9723 mtr_commit(&mtr);
9724
9725 if (rotate_ok) {
9726 ++rotate_count;
9727 if (fsp_is_ibd_tablespace(space_id)) {
9728 if (fsp_is_file_per_table(space_id, space->flags)) {
9729 ib::info(ER_IB_MSG_REENCRYPTED_TABLESPACE_KEY, space->name);
9730 } else {
9731 ib::info(ER_IB_MSG_REENCRYPTED_GENERAL_TABLESPACE_KEY, space->name);
9732 }
9733 }
9734 } else {
9735 ++fail_count;
9736 }
9737 }
9738
9739 /* The operation should finish successfully for all tablespaces */
9740 ut_a(fail_count == 0);
9741 }
9742
9743 10534 size_t fil_encryption_rotate() { return (fil_system->encryption_rotate()); }
9744
9745 9331 void fil_encryption_reencrypt(std::vector<space_id_t> &sid_vector) {
9746 9331 fil_system->encryption_reencrypt(sid_vector);
9747 9331 }
9748
9749 #endif /* !UNIV_HOTBACKUP */
9750
9751 /** Constructor
9752 @param[in] path pathname (may also include the file basename)
9753 @param[in] normalize_path If false, it's the callers responsibility to
9754 ensure that the path is normalized. */
9755 629645 Fil_path::Fil_path(const std::string &path, bool normalize_path)
9756 629645 : m_path(path) {
9757
2/2
✓ Branch 0 taken 21196 times.
✓ Branch 1 taken 608449 times.
629645 if (normalize_path) {
9758 21196 normalize(m_path);
9759 }
9760
9761
1/2
✓ Branch 0 taken 629645 times.
✗ Branch 1 not taken.
629645 m_abs_path = get_real_path(m_path, false);
9762 629645 }
9763
9764 /** Constructor
9765 @param[in] path Path, not necessarily NUL terminated
9766 @param[in] normalize_path If false, it's the callers responsibility to
9767 ensure that the path is normalized. */
9768
1/2
✓ Branch 0 taken 19363 times.
✗ Branch 1 not taken.
19363 Fil_path::Fil_path(const char *path, bool normalize_path) : m_path(path) {
9769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19363 times.
19363 if (normalize_path) {
9770 normalize(m_path);
9771 }
9772
9773
1/2
✓ Branch 0 taken 19363 times.
✗ Branch 1 not taken.
19363 m_abs_path = get_real_path(m_path, false);
9774 19363 }
9775
9776 /** Constructor
9777 @param[in] path Path, not necessarily NUL terminated
9778 @param[in] len Length of path
9779 @param[in] normalize_path If false, it's the callers responsibility to
9780 ensure that the path is normalized. */
9781 55449 Fil_path::Fil_path(const char *path, size_t len, bool normalize_path)
9782
1/2
✓ Branch 0 taken 55449 times.
✗ Branch 1 not taken.
55449 : m_path(path, len) {
9783
1/2
✓ Branch 0 taken 55449 times.
✗ Branch 1 not taken.
55449 if (normalize_path) {
9784 55449 normalize(m_path);
9785 }
9786
9787
1/2
✓ Branch 0 taken 55449 times.
✗ Branch 1 not taken.
55449 m_abs_path = get_real_path(m_path, false);
9788 55449 }
9789
9790 /** Default constructor. */
9791 20300 Fil_path::Fil_path() : m_path(), m_abs_path() { /* No op */
9792 20300 }
9793
9794 38038 bool Fil_path::is_same_as(const Fil_path &other) const {
9795
3/6
✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38038 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 38038 times.
38038 if (path().empty() || other.path().empty()) {
9796 return false;
9797 }
9798
9799
1/2
✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
38038 std::string first = abs_path();
9800
1/2
✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
38038 trim_separator(first);
9801
9802
1/2
✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
38038 std::string second = other.abs_path();
9803
1/2
✓ Branch 0 taken 38038 times.
✗ Branch 1 not taken.
38038 trim_separator(second);
9804
9805 38038 return (first == second);
9806 38038 }
9807
9808 9623 bool Fil_path::is_same_as(const std::string &other) const {
9809
3/6
✓ Branch 0 taken 9623 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9623 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9623 times.
9623 if (path().empty() || other.empty()) {
9810 return false;
9811 }
9812
9813
1/2
✓ Branch 0 taken 9623 times.
✗ Branch 1 not taken.
9623 Fil_path other_path(other);
9814
9815
1/2
✓ Branch 0 taken 9623 times.
✗ Branch 1 not taken.
9623 return is_same_as(other_path);
9816 9623 }
9817
9818 498 std::pair<std::string, std::string> Fil_path::split(const std::string &path) {
9819 498 const auto n = path.rfind(OS_PATH_SEPARATOR);
9820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 ut_ad(n != std::string::npos);
9821
1/2
✓ Branch 0 taken 498 times.
✗ Branch 1 not taken.
498 return {path.substr(0, n), path.substr(n)};
9822 }
9823
9824 73071 bool Fil_path::is_ancestor(const Fil_path &other) const {
9825
3/6
✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73071 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 73071 times.
73071 if (path().empty() || other.path().empty()) {
9826 return false;
9827 }
9828
9829
1/2
✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
73071 std::string ancestor = abs_path();
9830
1/2
✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
73071 std::string descendant = other.abs_path();
9831
9832 /* We do not know if the descendant is a dir or a file.
9833 But the ancestor in this routine is always a directory.
9834 If it does not yet exist, it may not have a trailing separator.
9835 If there is no trailing separator, add it. */
9836
1/2
✓ Branch 0 taken 73071 times.
✗ Branch 1 not taken.
73071 append_separator(ancestor);
9837
9838
2/2
✓ Branch 0 taken 22283 times.
✓ Branch 1 taken 50788 times.
73071 if (descendant.length() <= ancestor.length()) {
9839 22283 return false;
9840 }
9841
9842
1/2
✓ Branch 0 taken 50788 times.
✗ Branch 1 not taken.
50788 return std::equal(ancestor.begin(), ancestor.end(), descendant.begin());
9843 73071 }
9844
9845 9737 bool Fil_path::is_ancestor(const std::string &other) const {
9846
3/6
✓ Branch 0 taken 9737 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9737 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9737 times.
9737 if (path().empty() || other.empty()) {
9847 return false;
9848 }
9849
9850
1/2
✓ Branch 0 taken 9737 times.
✗ Branch 1 not taken.
9737 Fil_path descendant(other);
9851
9852
1/2
✓ Branch 0 taken 9737 times.
✗ Branch 1 not taken.
9737 return is_ancestor(descendant);
9853 9737 }
9854
9855 2886954 bool Fil_path::is_hidden(std::string path) {
9856
1/2
✓ Branch 0 taken 2886954 times.
✗ Branch 1 not taken.
2886954 std::string basename(path);
9857
1/2
✓ Branch 0 taken 2925134 times.
✗ Branch 1 not taken.
2925134 while (!basename.empty()) {
9858 2925134 char c = basename.back();
9859
5/6
✓ Branch 0 taken 2886954 times.
✓ Branch 1 taken 38180 times.
✓ Branch 2 taken 2886954 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2886954 times.
✓ Branch 5 taken 38180 times.
2925134 if (!(Fil_path::is_separator(c) || c == '*')) {
9860 2886954 break;
9861 }
9862
1/2
✓ Branch 0 taken 38180 times.
✗ Branch 1 not taken.
38180 basename.resize(basename.size() - 1);
9863 }
9864 2886954 auto sep = basename.find_last_of(SEPARATOR);
9865
9866
5/6
✓ Branch 0 taken 2886798 times.
✓ Branch 1 taken 156 times.
✓ Branch 2 taken 2886798 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2886796 times.
5773908 return (sep != std::string::npos && basename[sep + 1] == '.');
9867 2886954 }
9868
9869 #ifdef _WIN32
9870 bool Fil_path::is_hidden(WIN32_FIND_DATA &dirent) {
9871 if (dirent.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
9872 dirent.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
9873 return true;
9874 }
9875
9876 return false;
9877 }
9878 #endif /* WIN32 */
9879
9880 /** @return true if the path exists and is a file . */
9881 3860860 os_file_type_t Fil_path::get_file_type(const std::string &path) {
9882 os_file_type_t type;
9883
9884
1/2
✓ Branch 0 taken 3860861 times.
✗ Branch 1 not taken.
3860860 os_file_status(path.c_str(), nullptr, &type);
9885
9886 3860861 return type;
9887 }
9888
9889 /** Return a string to display the file type of a path.
9890 @param[in] path path name
9891 @return true if the path exists and is a file . */
9892 const char *Fil_path::get_file_type_string(const std::string &path) {
9893 return get_file_type_string(Fil_path::get_file_type(path));
9894 }
9895
9896 /** Return a string to display the file type of a path.
9897 @param[in] type OS file type
9898 @return true if the path exists and is a file . */
9899 const char *Fil_path::get_file_type_string(os_file_type_t type) {
9900 switch (type) {
9901 case OS_FILE_TYPE_FILE:
9902 return "file";
9903 case OS_FILE_TYPE_LINK:
9904 return "symbolic link";
9905 case OS_FILE_TYPE_DIR:
9906 return "directory";
9907 case OS_FILE_TYPE_BLOCK:
9908 return "block device";
9909 case OS_FILE_TYPE_NAME_TOO_LONG:
9910 return "name too long";
9911 case OS_FILE_PERMISSION_ERROR:
9912 return "permission error";
9913 case OS_FILE_TYPE_MISSING:
9914 return "missing";
9915 case OS_FILE_TYPE_UNKNOWN:
9916 case OS_FILE_TYPE_FAILED:
9917 break;
9918 }
9919 return "unknown";
9920 }
9921
9922 /** @return true if the path exists and is a file . */
9923 bool Fil_path::is_file_and_exists() const {
9924 return (get_file_type(abs_path()) == OS_FILE_TYPE_FILE);
9925 }
9926
9927 /** @return true if the path exists and is a directory. */
9928 1364 bool Fil_path::is_directory_and_exists() const {
9929
1/2
✓ Branch 0 taken 1364 times.
✗ Branch 1 not taken.
1364 return (get_file_type(abs_path()) == OS_FILE_TYPE_DIR);
9930 }
9931
9932 /** This validation is only for ':'.
9933 @return true if the path is valid. */
9934 1310 bool Fil_path::is_valid() const {
9935
1/2
✓ Branch 0 taken 1310 times.
✗ Branch 1 not taken.
1310 auto count = std::count(m_path.begin(), m_path.end(), ':');
9936
9937
2/2
✓ Branch 0 taken 1308 times.
✓ Branch 1 taken 2 times.
1310 if (count == 0) {
9938 1308 return true;
9939 }
9940
9941 #ifdef _WIN32
9942 /* Do not allow names like "C:name.ibd" because it
9943 specifies the "C:" drive but allows a relative location.
9944 It should be like "c:\". If a single colon is used it
9945 must be the second byte and the third byte must be a
9946 separator. */
9947
9948 /* 8 == strlen("c:\a,ibd") */
9949 if (count == 1 && m_path.length() >= 8 && isalpha(m_path.at(0)) &&
9950 m_path.at(1) == ':' && (m_path.at(2) == '\\' || m_path.at(2) == '/')) {
9951 return true;
9952 }
9953 #endif /* _WIN32 */
9954
9955 2 return false;
9956 }
9957
9958 1646 bool Fil_path::is_circular() const {
9959 size_t first;
9960
9961 /* Find the first named directory. It is OK for a path to
9962 start with "../../../dir". */
9963
6/6
✓ Branch 0 taken 2041 times.
✓ Branch 1 taken 413 times.
✓ Branch 2 taken 395 times.
✓ Branch 3 taken 1646 times.
✓ Branch 4 taken 808 times.
✓ Branch 5 taken 1646 times.
2454 for (first = 0; m_path[first] == OS_SEPARATOR || m_path[first] == '.';
9964 ++first)
9965 ;
9966
9967 1646 size_t back_up = m_path.find(SLASH_DOT_DOT_SLASH, first);
9968
2/2
✓ Branch 0 taken 1637 times.
✓ Branch 1 taken 9 times.
1646 if (back_up == std::string::npos) {
9969 1637 return false;
9970 }
9971
9972 #ifndef _WIN32
9973 /* If the path contains a symlink before the /../ and the platform
9974 is not Windows, then '/../' does not go bback through the symlink,
9975 so it is not circular. It refers to the parent of the symlinked
9976 location and we must allow it. On Windows, it backs up to the directory
9977 where the symlink starts, which is a circular reference. */
9978
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 std::string up_path = m_path.substr(0, back_up);
9979
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (my_is_symlink(up_path.c_str(), nullptr)) {
9980 return false;
9981 }
9982 #endif /* _WIN32 */
9983
9984 9 return true;
9985 9 }
9986
9987 /** Sets the flags of the tablespace. The tablespace must be locked
9988 in MDL_EXCLUSIVE MODE.
9989 @param[in] space tablespace in-memory struct
9990 @param[in] flags tablespace flags */
9991 205694 void fil_space_set_flags(fil_space_t *space, uint32_t flags) {
9992
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205694 times.
205694 ut_ad(fsp_flags_is_valid(flags));
9993
9994 205694 rw_lock_x_lock(&space->latch, UT_LOCATION_HERE);
9995
9996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205694 times.
205694 ut_a(flags < std::numeric_limits<uint32_t>::max());
9997 205694 space->flags = (uint32_t)flags;
9998
9999 205694 rw_lock_x_unlock(&space->latch);
10000 205694 }
10001
10002 /* Unit Tests */
10003 #ifdef UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH
10004 #define MF Fil_path::make
10005 #define DISPLAY ib::info(ER_IB_MSG_342) << path
10006 void test_make_filepath() {
10007 char *path;
10008 const char *long_path =
10009 "this/is/a/very/long/path/including/a/very/"
10010 "looooooooooooooooooooooooooooooooooooooooooooooooo"
10011 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10012 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10013 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10014 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10015 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10016 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10017 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10018 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10019 "oooooooooooooooooooooooooooooooooooooooooooooooong"
10020 "/folder/name";
10021 path = MF("/this/is/a/path/with/a/filename", nullptr, IBD, false);
10022 DISPLAY;
10023 path = MF("/this/is/a/path/with/a/filename", nullptr, ISL, false);
10024 DISPLAY;
10025 path = MF("/this/is/a/path/with/a/filename", nullptr, CFG, false);
10026 DISPLAY;
10027 path = MF("/this/is/a/path/with/a/filename", nullptr, CFP, false);
10028 DISPLAY;
10029 path = MF("/this/is/a/path/with/a/filename.ibd", nullptr, IBD, false);
10030 DISPLAY;
10031 path = MF("/this/is/a/path/with/a/filename.ibd", nullptr, IBD, false);
10032 DISPLAY;
10033 path = MF("/this/is/a/path/with/a/filename.dat", nullptr, IBD, false);
10034 DISPLAY;
10035 path = MF(nullptr, "tablespacename", NO_EXT, false);
10036 DISPLAY;
10037 path = MF(nullptr, "tablespacename", IBD, false);
10038 DISPLAY;
10039 path = MF(nullptr, "dbname/tablespacename", NO_EXT, false);
10040 DISPLAY;
10041 path = MF(nullptr, "dbname/tablespacename", IBD, false);
10042 DISPLAY;
10043 path = MF(nullptr, "dbname/tablespacename", ISL, false);
10044 DISPLAY;
10045 path = MF(nullptr, "dbname/tablespacename", CFG, false);
10046 DISPLAY;
10047 path = MF(nullptr, "dbname/tablespacename", CFP, false);
10048 DISPLAY;
10049 path = MF(nullptr, "dbname\\tablespacename", NO_EXT, false);
10050 DISPLAY;
10051 path = MF(nullptr, "dbname\\tablespacename", IBD, false);
10052 DISPLAY;
10053 path = MF("/this/is/a/path", "dbname/tablespacename", IBD, false);
10054 DISPLAY;
10055 path = MF("/this/is/a/path", "dbname/tablespacename", IBD, true);
10056 DISPLAY;
10057 path = MF("./this/is/a/path", "dbname/tablespacename.ibd", IBD, true);
10058 DISPLAY;
10059 path = MF("this\\is\\a\\path", "dbname/tablespacename", IBD, true);
10060 DISPLAY;
10061 path = MF("/this/is/a/path", "dbname\\tablespacename", IBD, true);
10062 DISPLAY;
10063 path = MF(long_path, nullptr, IBD, false);
10064 DISPLAY;
10065 path = MF(long_path, "tablespacename", IBD, false);
10066 DISPLAY;
10067 path = MF(long_path, "tablespacename", IBD, true);
10068 DISPLAY;
10069 }
10070 #endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
10071
10072 /** Release the reserved free extents.
10073 @param[in] n_reserved number of reserved extents */
10074 void fil_space_t::release_free_extents(ulint n_reserved) {
10075 #ifndef UNIV_HOTBACKUP
10076 ut_ad(rw_lock_own(&latch, RW_LOCK_X));
10077 #endif /* !UNIV_HOTBACKUP */
10078
10079 ut_a(n_reserved < std::numeric_limits<uint32_t>::max());
10080 ut_a(n_reserved_extents >= n_reserved);
10081
10082 n_reserved_extents -= (uint32_t)n_reserved;
10083 }
10084
10085 #ifndef UNIV_HOTBACKUP
10086
10087 #ifdef UNIV_DEBUG
10088
10089 /** Print the extent descriptor pages of this tablespace into
10090 the given file.
10091 @param[in] filename the output file name. */
10092 void fil_space_t::print_xdes_pages(const char *filename) const {
10093 std::ofstream out(filename);
10094 print_xdes_pages(out);
10095 }
10096
10097 /** Print the extent descriptor pages of this tablespace into
10098 the given output stream.
10099 @param[in] out the output stream.
10100 @return the output stream. */
10101 std::ostream &fil_space_t::print_xdes_pages(std::ostream &out) const {
10102 mtr_t mtr;
10103 const page_size_t page_size(flags);
10104
10105 mtr_start(&mtr);
10106
10107 for (page_no_t i = 0; i < 100; ++i) {
10108 page_no_t xdes_page_no = i * UNIV_PAGE_SIZE;
10109
10110 if (xdes_page_no >= size) {
10111 break;
10112 }
10113
10114 buf_block_t *xdes_block =
10115 buf_page_get(page_id_t(id, xdes_page_no), page_size, RW_S_LATCH,
10116 UT_LOCATION_HERE, &mtr);
10117
10118 page_t *page = buf_block_get_frame(xdes_block);
10119
10120 ulint page_type = fil_page_get_type(page);
10121
10122 switch (page_type) {
10123 case FIL_PAGE_TYPE_ALLOCATED:
10124
10125 ut_ad(xdes_page_no >= free_limit);
10126
10127 mtr_commit(&mtr);
10128 return out;
10129
10130 case FIL_PAGE_TYPE_FSP_HDR:
10131 case FIL_PAGE_TYPE_XDES:
10132 break;
10133 default:
10134 ut_error;
10135 }
10136
10137 xdes_page_print(out, page, xdes_page_no, &mtr);
10138 }
10139
10140 mtr_commit(&mtr);
10141 return out;
10142 }
10143 #endif /* UNIV_DEBUG */
10144
10145 /** Initialize the table space encryption
10146 @param[in,out] space Tablespace instance */
10147 172 static void fil_tablespace_encryption_init(const fil_space_t *space) {
10148
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 172 times.
409 for (auto &key : *recv_sys->keys) {
10149
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 66 times.
237 if (key.space_id != space->id) {
10150 171 continue;
10151 }
10152
10153 66 dberr_t err = DB_SUCCESS;
10154
10155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 ut_ad(!fsp_is_system_tablespace(space->id));
10156
10157
3/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 42 times.
66 if (fsp_is_file_per_table(space->id, space->flags)) {
10158 /* For file-per-table tablespace, which is not INPLACE algorithm, copy
10159 what is found on REDO Log. */
10160
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv);
10161 } else {
10162 /* Here we try to populate space tablespace_key which is read during
10163 REDO scan.
10164
10165 Consider following scenario:
10166 1. Alter tablespce .. encrypt=y (KEY1)
10167 2. Alter tablespce .. encrypt=n
10168 3. Alter tablespce .. encrypt=y (KEY2)
10169
10170 Lets say there is a crash after (3) is finished successfully. Let's say
10171 we scanned till REDO of (1) but couldn't reach to REDO of (3).
10172
10173 During recovery:
10174 ----------------
10175 Case 1:
10176 - Before crash, pages of tablespace were encrypted with KEY2 and flushed.
10177 - In recovery, on REDO we've got tablespace key as KEY1.
10178 - Note, during tablespce load, KEY2 would have been found on page 0 and
10179 thus loaded already in file_space_t.
10180 - If we overwrite this space key (KEY2) with the one we got from REDO log
10181 scan (KEY1), then when we try to read a page from Disk, we will try to
10182 decrypt it using KEY1 whereas page was encrypted with KEY2. ERROR.
10183 - So don't overwrite keys on tablespace in this scenario.
10184
10185 Case 2:
10186 - Before crash, if tablespace pages were not flushed.
10187 - On disk, there may be
10188 - No Key (after decrypt page 0 was flushed)
10189 - KEY1 (after decrypt, page 0 wasn't flushed)
10190 - KEY2. (After 3 starts, page 0 was flushed)
10191 Thus tablespace would have been loaded accordingly.
10192
10193 This function is called only during recovery when a tablespce is loaded.
10194 So we can see the LSN for REDO Entry (recv_sys->keys) and compare it with
10195 the LSN of page 0 and take decision of updating encryption accordingly. */
10196
10197
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 if (space->m_encryption_metadata.m_key_len == 0 ||
10198
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 key.lsn > space->m_header_page_flush_lsn) {
10199 /* Key on tablesapce isn't present or old. Update it. */
10200
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv);
10201 } else {
10202 /* Key on tablespace is new. Skip updating. */
10203 }
10204 }
10205
10206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (err != DB_SUCCESS) {
10207 ib::error(ER_IB_MSG_343) << "Can't set encryption information"
10208 << " for tablespace" << space->name << "!";
10209 }
10210
10211 66 ut::free(key.iv);
10212 66 ut::free(key.ptr);
10213
10214 66 key.iv = nullptr;
10215 66 key.ptr = nullptr;
10216
10217 66 key.space_id = std::numeric_limits<space_id_t>::max();
10218 }
10219 172 }
10220
10221 /** Modify table name in Innodb persistent stat tables, if needed. Required
10222 when partitioned table file names from old versions are modified to change
10223 the letter case.
10224 @param[in] old_path path to old file
10225 @param[in] new_path path to new file */
10226 226 static void fil_adjust_partition_stat(const std::string &old_path,
10227 const std::string &new_path) {
10228 char errstr[FN_REFLEN];
10229 226 std::string path;
10230
10231 /* Skip if not IBD file extension. */
10232
5/6
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 207 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 207 times.
433 if (!Fil_path::has_suffix(IBD, old_path) ||
10233
2/4
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 207 times.
207 !Fil_path::has_suffix(IBD, new_path)) {
10234 19 return;
10235 }
10236
10237 /* Check if partitioned table. */
10238
5/6
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 200 times.
407 if (!dict_name::is_partition(old_path) ||
10239
2/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
200 !dict_name::is_partition(new_path)) {
10240 7 return;
10241 }
10242
10243 200 std::string old_name;
10244
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 path.assign(old_path);
10245
2/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
200 if (!Fil_path::parse_file_path(path, IBD, old_name)) {
10246 return;
10247 }
10248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 ut_ad(!old_name.empty());
10249
10250 200 std::string new_name;
10251
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 path.assign(new_path);
10252
2/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
200 if (!Fil_path::parse_file_path(path, IBD, new_name)) {
10253 return;
10254 }
10255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 ut_ad(!new_name.empty());
10256
10257 /* Required for case insensitive file system where file path letter case
10258 doesn't matter. We need to keep the name in stat table consistent. */
10259
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 dict_name::rebuild(new_name);
10260
10261
3/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 79 times.
200 if (old_name.compare(new_name) != 0) {
10262
1/2
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
121 dict_stats_rename_table(old_name.c_str(), new_name.c_str(), errstr,
10263 sizeof(errstr));
10264 }
10265
4/6
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 200 times.
✓ Branch 5 taken 26 times.
226 }
10266
10267 /** Update the DD if any files were moved to a new location.
10268 Free the Tablespace_files instance.
10269 @param[in] read_only_mode true if InnoDB is started in read only mode.
10270 @return DB_SUCCESS if all OK */
10271 9614 dberr_t Fil_system::prepare_open_for_business(bool read_only_mode) {
10272
4/6
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 9573 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9614 times.
9614 if (read_only_mode && !m_moved.empty()) {
10273 ib::error(ER_IB_MSG_344)
10274 << m_moved.size() << " files have been relocated"
10275 << " and the server has been started in read"
10276 << " only mode. Cannot update the data dictionary.";
10277
10278 return DB_READ_ONLY;
10279 }
10280
10281
2/4
✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9614 times.
✗ Branch 3 not taken.
9614 trx_t *trx = check_trx_exists(current_thd);
10282
10283
1/2
✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
9614 TrxInInnoDB trx_in_innodb(trx);
10284
10285 /* The transaction should not be active yet, start it */
10286
10287 9614 trx->isolation_level = trx_t::READ_UNCOMMITTED;
10288
10289
1/2
✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
9614 trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE);
10290
10291 9614 size_t count = 0;
10292 9614 size_t failed = 0;
10293 9614 size_t batch_size = 0;
10294 9614 bool print_msg = false;
10295 9614 auto start_time = std::chrono::steady_clock::now();
10296
10297 /* If some file paths have changed then update the DD */
10298
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 9614 times.
9840 for (auto &tablespace : m_moved) {
10299 dberr_t err;
10300
10301
1/2
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
226 auto old_path = std::get<dd_fil::OLD_PATH>(tablespace);
10302
10303
1/2
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
226 auto space_name = std::get<dd_fil::SPACE_NAME>(tablespace);
10304
10305
1/2
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
226 auto new_path = std::get<dd_fil::NEW_PATH>(tablespace);
10306 226 auto object_id = std::get<dd_fil::OBJECT_ID>(tablespace);
10307
10308 /* We already have the space name in system cs. */
10309
1/2
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
226 err = dd_tablespace_rename(object_id, true, space_name.c_str(),
10310 new_path.c_str());
10311
10312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 226 times.
226 if (err != DB_SUCCESS) {
10313 ib::error(ER_IB_MSG_345) << "Unable to update tablespace ID"
10314 << " " << object_id << " "
10315 << " '" << old_path << "' to"
10316 << " '" << new_path << "'";
10317
10318 ++failed;
10319 }
10320
10321 /* Update persistent stat table if table name is modified. */
10322
1/2
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
226 fil_adjust_partition_stat(old_path, new_path);
10323
10324 226 ++count;
10325
10326
3/6
✓ Branch 0 taken 226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 226 times.
226 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
10327 ib::info(ER_IB_MSG_346) << "Processed " << count << "/" << m_moved.size()
10328 << " tablespace paths. Failures " << failed;
10329
10330 start_time = std::chrono::steady_clock::now();
10331 print_msg = true;
10332 }
10333
10334 226 ++batch_size;
10335
10336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 226 times.
226 if (batch_size > 10000) {
10337 innobase_commit_low(trx);
10338
10339 ib::info(ER_IB_MSG_347) << "Committed : " << batch_size;
10340
10341 batch_size = 0;
10342
10343 trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE);
10344 }
10345 226 }
10346
10347
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 9586 times.
9614 if (batch_size > 0) {
10348
3/6
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 ib::info(ER_IB_MSG_348) << "Committed : " << batch_size;
10349 }
10350
10351
1/2
✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
9614 innobase_commit_low(trx);
10352
10353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9614 times.
9614 if (print_msg) {
10354 ib::info(ER_IB_MSG_349) << "Updated " << count << " tablespace paths"
10355 << ", failures " << failed;
10356 }
10357
10358
1/2
✓ Branch 0 taken 9614 times.
✗ Branch 1 not taken.
9614 return failed == 0 ? DB_SUCCESS : DB_ERROR;
10359 9614 }
10360
10361 /** Free the Tablespace_files instance.
10362 @param[in] read_only_mode true if InnoDB is started in read only mode.
10363 @return DB_SUCCESS if all OK */
10364 9614 dberr_t fil_open_for_business(bool read_only_mode) {
10365 9614 return fil_system->prepare_open_for_business(read_only_mode);
10366 }
10367
10368 /** Replay a file rename operation for ddl replay.
10369 @param[in] page_id Space ID and first page number in the file
10370 @param[in] old_name old file name
10371 @param[in] new_name new file name
10372 @return whether the operation was successfully applied (the name did not
10373 exist, or new_name did not exist and name was successfully renamed to
10374 new_name) */
10375 694 bool fil_op_replay_rename_for_ddl(const page_id_t &page_id,
10376 const char *old_name, const char *new_name) {
10377 694 space_id_t space_id = page_id.space();
10378
1/2
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
694 fil_space_t *space = fil_space_get(space_id);
10379
10380
5/8
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 679 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 694 times.
694 if (space == nullptr && !fil_system->open_for_recovery(space_id)) {
10381 ib::info(ER_IB_MSG_350)
10382 << "Can not find space with space ID " << space_id
10383 << " when replaying the DDL log "
10384 << "rename from '" << old_name << "' to '" << new_name << "'";
10385
10386 return true;
10387 }
10388
10389
3/6
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 694 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 694 times.
✗ Branch 5 not taken.
694 return fil_op_replay_rename(page_id, old_name, new_name);
10390 }
10391
10392 /** Lookup the tablespace ID for recovery and DDL log apply.
10393 @param[in] space_id Tablespace ID to lookup
10394 @return true if the space ID is known. */
10395 18813427 bool Fil_system::lookup_for_recovery(space_id_t space_id) {
10396
4/6
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 18813412 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18813427 times.
18813427 ut_ad(recv_recovery_is_on() || Log_DDL::is_in_recovery());
10397
10398 /* Single threaded code, no need to acquire mutex. */
10399
1/2
✓ Branch 0 taken 18813427 times.
✗ Branch 1 not taken.
18813427 const auto result = get_scanned_filename_by_space_id(space_id);
10400
10401
2/2
✓ Branch 0 taken 18813412 times.
✓ Branch 1 taken 15 times.
18813427 if (recv_recovery_is_on()) {
10402 18813412 const auto &end = recv_sys->deleted.end();
10403
1/2
✓ Branch 0 taken 18813412 times.
✗ Branch 1 not taken.
18813412 const auto &it = recv_sys->deleted.find(space_id);
10404
10405
2/2
✓ Branch 0 taken 1405205 times.
✓ Branch 1 taken 17408207 times.
18813412 if (result.second == nullptr) {
10406 /* If it wasn't deleted after finding it on disk then
10407 we tag it as missing. */
10408
10409
2/2
✓ Branch 0 taken 1405201 times.
✓ Branch 1 taken 4 times.
1405205 if (it == end) {
10410
1/2
✓ Branch 0 taken 1405201 times.
✗ Branch 1 not taken.
1405201 recv_sys->missing_ids.insert(space_id);
10411 }
10412
10413 1405205 return false;
10414 }
10415
10416 /* Check that it wasn't deleted. */
10417
10418 17408207 return (it == end);
10419 }
10420
10421 15 return (result.second != nullptr);
10422 18813427 }
10423
10424 /** Lookup the tablespace ID.
10425 @param[in] space_id Tablespace ID to lookup
10426 @return true if the space ID is known. */
10427 18797290 bool fil_tablespace_lookup_for_recovery(space_id_t space_id) {
10428 18797290 return fil_system->lookup_for_recovery(space_id);
10429 }
10430
10431 16137 dberr_t Fil_system::open_for_recovery(space_id_t space_id) {
10432
4/6
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 16122 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16137 times.
16137 ut_ad(recv_recovery_is_on() || Log_DDL::is_in_recovery());
10433
10434
3/4
✓ Branch 0 taken 16137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 16131 times.
16137 if (!lookup_for_recovery(space_id)) {
10435 6 return DB_FAIL;
10436 }
10437
10438
1/2
✓ Branch 0 taken 16131 times.
✗ Branch 1 not taken.
16131 const auto result = get_scanned_filename_by_space_id(space_id);
10439
10440 /* Duplicates should have been sorted out before start of recovery. */
10441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16131 times.
16131 ut_a(result.second->size() == 1);
10442
10443 16131 const auto &filename = result.second->front();
10444
1/2
✓ Branch 0 taken 16131 times.
✗ Branch 1 not taken.
16131 const std::string path = result.first + filename;
10445
10446 fil_space_t *space;
10447
10448
1/2
✓ Branch 0 taken 16131 times.
✗ Branch 1 not taken.
16131 auto status = ibd_open_for_recovery(space_id, path, space);
10449
10450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16131 times.
16131 if (status == FIL_LOAD_DBWLR_CORRUPTION) {
10451 return DB_CORRUPTION;
10452 }
10453
10454 16131 dberr_t err = DB_SUCCESS;
10455
10456
2/2
✓ Branch 0 taken 16117 times.
✓ Branch 1 taken 14 times.
16131 if (status == FIL_LOAD_OK) {
10457 16117 if ((FSP_FLAGS_GET_ENCRYPTION(space->flags) ||
10458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15020 times.
15020 space->encryption_op_in_progress ==
10459
4/4
✓ Branch 0 taken 15020 times.
✓ Branch 1 taken 1097 times.
✓ Branch 2 taken 172 times.
✓ Branch 3 taken 15945 times.
32234 Encryption::Progress::ENCRYPTION) &&
10460
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 925 times.
1097 recv_sys->keys != nullptr) {
10461
1/2
✓ Branch 0 taken 172 times.
✗ Branch 1 not taken.
172 fil_tablespace_encryption_init(space);
10462 }
10463
10464
1/2
✓ Branch 0 taken 16117 times.
✗ Branch 1 not taken.
16117 if (!recv_sys->dblwr->empty()) {
10465 16117 err = recv_sys->dblwr->recover(space);
10466
10467 } else {
10468 ib::info(ER_IB_MSG_DBLWR_1317) << "DBLWR recovery skipped for "
10469 << space->name << " ID: " << space->id;
10470 }
10471
10472 16117 return err;
10473 }
10474
10475 14 return DB_FAIL;
10476 16131 }
10477
10478 16122 dberr_t fil_tablespace_open_for_recovery(space_id_t space_id) {
10479 16122 return fil_system->open_for_recovery(space_id);
10480 }
10481
10482 72421 Fil_state fil_tablespace_path_equals(space_id_t space_id,
10483 const char *space_name, ulint fsp_flags,
10484 std::string old_path,
10485 std::string *new_path) {
10486
8/14
✓ Branch 0 taken 72421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53493 times.
✓ Branch 3 taken 18928 times.
✓ Branch 4 taken 53493 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 53493 times.
✓ Branch 8 taken 18928 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18928 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 72421 times.
72421 ut_ad((fsp_is_ibd_tablespace(space_id) &&
10487 Fil_path::has_suffix(IBD, old_path)) ||
10488 fsp_is_undo_tablespace(space_id));
10489
10490 /* Watch out for implicit undo tablespaces that are created during startup.
10491 They will not be in the list of scanned files. But the DD might need to be
10492 updated if the undo directory is different now from when the database was
10493 initialized. The DD will be updated if we put it in fil_system->moved. */
10494
3/4
✓ Branch 0 taken 72421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18928 times.
✓ Branch 3 taken 53493 times.
72421 if (fsp_is_undo_tablespace(space_id)) {
10495
1/2
✓ Branch 0 taken 18928 times.
✗ Branch 1 not taken.
18928 undo::spaces->s_lock();
10496 18928 space_id_t space_num = undo::id2num(space_id);
10497
1/2
✓ Branch 0 taken 18928 times.
✗ Branch 1 not taken.
18928 undo::Tablespace *undo_space = undo::spaces->find(space_num);
10498
10499
6/6
✓ Branch 0 taken 18925 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 18903 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 18906 times.
18928 if (undo_space != nullptr && undo_space->is_new()) {
10500
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
22 *new_path = undo_space->file_name();
10501
3/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 4 times.
22 Fil_state state = ((old_path.compare(*new_path) == 0) ? Fil_state::MATCHES
10502 22 : Fil_state::MOVED);
10503
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 undo::spaces->s_unlock();
10504 22 return state;
10505 }
10506
1/2
✓ Branch 0 taken 18906 times.
✗ Branch 1 not taken.
18906 undo::spaces->s_unlock();
10507 }
10508
10509 /* Single threaded code, no need to acquire mutex. */
10510 72399 const auto &end = recv_sys->deleted.end();
10511
1/2
✓ Branch 0 taken 72399 times.
✗ Branch 1 not taken.
72399 const auto &it = recv_sys->deleted.find(space_id);
10512
1/2
✓ Branch 0 taken 72399 times.
✗ Branch 1 not taken.
72399 const auto result = fil_system->get_scanned_filename_by_space_id(space_id);
10513
10514
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 72358 times.
72399 if (result.second == nullptr) {
10515 /* The file was not scanned but the DD has the tablespace. Either;
10516 1. This file is missing
10517 2. The file could not be opened because of encryption or something else,
10518 3. The path is not included in --innodb-directories.
10519 We need to check if the DD path is valid before we tag the file
10520 as missing. */
10521
10522
3/4
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 21 times.
41 if (Fil_path::get_file_type(old_path) == OS_FILE_TYPE_FILE) {
10523 /* This file from the DD exists where the DD thinks it is. It will be
10524 opened later. Make some noise if the location is unknown. */
10525
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 if (!fil_path_is_known(old_path)) {
10526
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 ib::warn(ER_IB_MSG_UNPROTECTED_LOCATION_ALLOWED, old_path.c_str(),
10527 space_name);
10528 }
10529 20 return Fil_state::MATCHES;
10530 }
10531
10532 /* If it wasn't deleted during redo apply, we tag it as missing. */
10533
10534
3/6
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
21 if (it == end && recv_recovery_is_on()) {
10535 recv_sys->missing_ids.insert(space_id);
10536 }
10537
10538 21 return Fil_state::MISSING;
10539 }
10540
10541 /* Check if it was deleted according to the redo log. */
10542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
72358 if (it != end) {
10543 return Fil_state::DELETED;
10544 }
10545
10546 /* A file with this space_id was found during scanning.
10547 Validate its location and check if it was moved from where
10548 the DD thinks it is.
10549
10550 Don't compare the full filename, there can be a mismatch if
10551 there was a DDL in progress and we will end up renaming the path
10552 in the DD dictionary. Such renames should be handled by the
10553 atomic DDL "ddl_log". */
10554
10555
1/2
✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
72358 std::string old_dir{old_path};
10556
10557 /* Ignore the filename component of the old path. */
10558 72358 auto pos = old_dir.find_last_of(Fil_path::SEPARATOR);
10559
2/2
✓ Branch 0 taken 10067 times.
✓ Branch 1 taken 62291 times.
72358 if (pos == std::string::npos) {
10560
1/2
✓ Branch 0 taken 10067 times.
✗ Branch 1 not taken.
10067 old_dir = MySQL_datadir_path;
10561 } else {
10562
1/2
✓ Branch 0 taken 62291 times.
✗ Branch 1 not taken.
62291 old_dir.resize(pos + 1);
10563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62291 times.
62291 ut_ad(Fil_path::is_separator(old_dir.back()));
10564 }
10565
1/2
✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
72358 old_dir = Fil_path::get_real_path(old_dir);
10566
10567 /* Build the new path from the scan path and the found path. */
10568
1/2
✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
72358 std::string new_dir{result.first};
10569
10570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
72358 ut_ad(Fil_path::is_separator(new_dir.back()));
10571
10572
1/2
✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
72358 new_dir.append(result.second->front());
10573
10574
1/2
✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
72358 new_dir = Fil_path::get_real_path(new_dir);
10575
10576 /* Do not use a datafile that is in the wrong place. */
10577
3/4
✓ Branch 0 taken 72358 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 72160 times.
72358 if (!Fil_path::is_valid_location(space_name, space_id, fsp_flags, new_dir)) {
10578 198 return Fil_state::MISSING;
10579 }
10580
10581 /* Ignore the filename component of the new path. */
10582 72160 pos = new_dir.find_last_of(Fil_path::SEPARATOR);
10583
10584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72160 times.
72160 ut_ad(pos != std::string::npos);
10585
10586
1/2
✓ Branch 0 taken 72160 times.
✗ Branch 1 not taken.
72160 new_dir.resize(pos + 1);
10587
10588
3/4
✓ Branch 0 taken 72160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 72073 times.
72160 if (old_dir.compare(new_dir) != 0) {
10589
1/2
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
87 *new_path = result.first + result.second->front();
10590 87 return Fil_state::MOVED;
10591 }
10592
10593
1/2
✓ Branch 0 taken 72073 times.
✗ Branch 1 not taken.
72073 *new_path = old_path;
10594 72073 return Fil_state::MATCHES;
10595 72399 }
10596
10597 226 void fil_add_moved_space(dd::Object_id dd_object_id, space_id_t space_id,
10598 const char *space_name, const std::string &old_path,
10599 const std::string &new_path) {
10600 /* Keep space_name in system cs. We handle it while modifying DD. */
10601 226 fil_system->moved(dd_object_id, space_id, space_name, old_path, new_path);
10602 226 }
10603
10604 273774 bool fil_update_partition_name(space_id_t space_id, uint32_t fsp_flags,
10605 bool update_space, std::string &space_name,
10606 std::string &dd_path) {
10607 #ifdef _WIN32
10608 /* Safe check. Never needed on Windows for path. */
10609 if (!update_space) {
10610 return false;
10611 }
10612 #endif /* WIN32 */
10613
10614 /* Never needed in case insensitive file system for path. */
10615
3/4
✓ Branch 0 taken 192793 times.
✓ Branch 1 taken 80981 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192793 times.
273774 if (!update_space && lower_case_file_system) {
10616 return false;
10617 }
10618
10619 /* Only needed for file per table. */
10620
7/8
✓ Branch 0 taken 80981 times.
✓ Branch 1 taken 192793 times.
✓ Branch 2 taken 80981 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28763 times.
✓ Branch 5 taken 52218 times.
✓ Branch 6 taken 28763 times.
✓ Branch 7 taken 245011 times.
273774 if (update_space && !fsp_is_file_per_table(space_id, fsp_flags)) {
10621 28763 return false;
10622 }
10623
10624 /* Extract dictionary name schema_name/table_name from dd path. */
10625 245011 std::string table_name;
10626
10627
3/4
✓ Branch 0 taken 245011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1234 times.
✓ Branch 3 taken 243777 times.
245011 if (!Fil_path::parse_file_path(dd_path, IBD, table_name)) {
10628 /* Not a valid file-per-table IBD path */
10629 1234 return false;
10630 }
10631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243777 times.
243777 ut_ad(!table_name.empty());
10632
10633 /* Only needed for partition file. */
10634
3/4
✓ Branch 0 taken 243777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 211424 times.
✓ Branch 3 taken 32353 times.
243777 if (!dict_name::is_partition(table_name)) {
10635 211424 return false;
10636 }
10637
10638 /* Rebuild dictionary name to convert partition names to lower case. */
10639
1/2
✓ Branch 0 taken 32353 times.
✗ Branch 1 not taken.
32353 dict_name::rebuild(table_name);
10640
10641
2/2
✓ Branch 0 taken 4302 times.
✓ Branch 1 taken 28051 times.
32353 if (update_space) {
10642 /* Rebuild space name if required. */
10643
1/2
✓ Branch 0 taken 4302 times.
✗ Branch 1 not taken.
4302 dict_name::rebuild_space(table_name, space_name);
10644 }
10645
10646 /* No need to update file name for lower case file system. */
10647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32353 times.
32353 if (lower_case_file_system) {
10648 return false;
10649 }
10650
10651 /* Rebuild path and compare. */
10652
1/2
✓ Branch 0 taken 32353 times.
✗ Branch 1 not taken.
32353 std::string table_path = Fil_path::make_new_path(dd_path, table_name, IBD);
10653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32353 times.
32353 ut_ad(!table_path.empty());
10654
10655
3/4
✓ Branch 0 taken 32353 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 638 times.
✓ Branch 3 taken 31715 times.
32353 if (dd_path.compare(table_path) != 0) {
10656 /* Validate that the file exists. */
10657
3/4
✓ Branch 0 taken 638 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 626 times.
✓ Branch 3 taken 12 times.
638 if (os_file_exists(table_path.c_str())) {
10658
1/2
✓ Branch 0 taken 626 times.
✗ Branch 1 not taken.
626 dd_path.assign(table_path);
10659 626 return true;
10660
10661 } else {
10662
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 ib::warn(ER_IB_WARN_OPEN_PARTITION_FILE, table_path.c_str());
10663 }
10664 }
10665
10666 31727 return false;
10667 245011 }
10668
10669 #endif /* !UNIV_HOTBACKUP */
10670
10671 /** This function should be called after recovery has completed.
10672 Check for tablespace files for which we did not see any MLOG_FILE_DELETE
10673 or MLOG_FILE_RENAME record. These could not be recovered.
10674 @return true if there were some filenames missing for which we had to
10675 ignore redo log records during the apply phase */
10676 9402 bool Fil_system::check_missing_tablespaces() {
10677 9402 bool missing = false;
10678 9402 const auto end = recv_sys->deleted.end();
10679
10680 /* Called in single threaded mode, no need to acquire the mutex. */
10681
10682 9402 recv_sys->dblwr->check_missing_tablespaces();
10683
10684
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9402 times.
9407 for (auto space_id : recv_sys->missing_ids) {
10685
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (recv_sys->deleted.find(space_id) != end) {
10686 continue;
10687 }
10688
10689
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 const auto result = get_scanned_filename_by_space_id(space_id);
10690
10691
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (result.second == nullptr) {
10692
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (fsp_is_undo_tablespace(space_id)) {
10693 /* This could happen if an undo truncate is in progress because
10694 undo tablespace construction is not redo logged. The DD is updated
10695 at the end and may be out of sync. */
10696 continue;
10697 }
10698
10699
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
10 ib::error(ER_IB_MSG_354) << "Could not find any file associated with"
10700
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 << " the tablespace ID: " << space_id;
10701 5 missing = true;
10702
10703 } else {
10704 ut_a(!result.second->empty());
10705 }
10706
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 }
10707
10708 9402 return missing;
10709 }
10710
10711 /** This function should be called after recovery has completed.
10712 Check for tablespace files for which we did not see any MLOG_FILE_DELETE
10713 or MLOG_FILE_RENAME record. These could not be recovered
10714 @return true if there were some filenames missing for which we had to
10715 ignore redo log records during the apply phase */
10716 9402 bool fil_check_missing_tablespaces() {
10717 9402 return fil_system->check_missing_tablespaces();
10718 }
10719
10720 /** Redo a tablespace create.
10721 @param[in] ptr redo log record
10722 @param[in] end end of the redo log buffer
10723 @param[in] page_id Tablespace Id and first page in file
10724 @param[in] parsed_bytes Number of bytes parsed so far
10725 @param[in] parse_only Don't apply, parse only
10726 @return pointer to next redo log record
10727 @retval nullptr if this log record was truncated */
10728 4478 byte *fil_tablespace_redo_create(byte *ptr, const byte *end,
10729 const page_id_t &page_id, ulint parsed_bytes,
10730 bool parse_only) {
10731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
4478 ut_a(page_id.page_no() == 0);
10732
10733 /* We never recreate the system tablespace. */
10734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
4478 ut_a(page_id.space() != TRX_SYS_SPACE);
10735
10736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
4478 ut_a(parsed_bytes != ULINT_UNDEFINED);
10737
10738 /* Where 6 = flags (uint32_t) + name len (uint16_t). */
10739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4478 times.
4478 if (end <= ptr + 6) {
10740 return nullptr;
10741 }
10742
10743 #ifdef UNIV_HOTBACKUP
10744 uint32_t flags = mach_read_from_4(ptr);
10745 #else
10746 /* Skip the flags, not used here. */
10747 #endif /* UNIV_HOTBACKUP */
10748
10749 4478 ptr += 4;
10750
10751 4478 ulint len = mach_read_from_2(ptr);
10752
10753 4478 ptr += 2;
10754
10755 /* Do we have the full/valid file name. */
10756
3/4
✓ Branch 0 taken 4476 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4476 times.
4478 if (end < ptr + len || len < 5) {
10757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len < 5) {
10758 char name[6];
10759
10760 snprintf(name, sizeof(name), "%.*s", (int)len, ptr);
10761
10762 ib::error(ER_IB_MSG_355) << "MLOG_FILE_CREATE : Invalid file name."
10763 << " Length (" << len << ") must be >= 5"
10764 << " and end in '.ibd'. File name in the"
10765 << " redo log is '" << name << "'";
10766
10767 recv_sys->found_corrupt_log = true;
10768 }
10769
10770 2 return nullptr;
10771 }
10772
10773 4476 char *name = reinterpret_cast<char *>(ptr);
10774
10775 4476 Fil_path::normalize(name);
10776
10777 4476 ptr += len;
10778
10779
7/16
✓ Branch 0 taken 4476 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4476 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 4449 times.
✓ Branch 6 taken 4476 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4476 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4476 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
4503 if (!(Fil_path::has_suffix(IBD, name) ||
10780
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 fsp_is_undo_tablespace(page_id.space()))) {
10781 recv_sys->found_corrupt_log = true;
10782
10783 return nullptr;
10784 }
10785
10786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4476 times.
4476 if (parse_only) {
10787 return ptr;
10788 }
10789 #ifdef UNIV_HOTBACKUP
10790
10791 meb_tablespace_redo_create(page_id, flags, name);
10792
10793 #else /* !UNIV_HOTBACKUP */
10794
10795 /* The first condition is true during normal server operation, the
10796 second one during server startup after
10797 recv_recovery_from_checkpoint_start has completed. */
10798
3/6
✓ Branch 0 taken 4476 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4476 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4476 times.
4476 if (!recv_recovery_is_on() || recv_lsn_checks_on) {
10799 /* We are being called from online log tracking, file name
10800 processing is a no-op, and specifically do not cause any DD
10801 changes. */
10802 return (ptr);
10803 }
10804
10805 const auto result =
10806
1/2
✓ Branch 0 taken 4476 times.
✗ Branch 1 not taken.
4476 fil_system->get_scanned_filename_by_space_id(page_id.space());
10807
10808
2/2
✓ Branch 0 taken 1423 times.
✓ Branch 1 taken 3053 times.
4476 if (result.second == nullptr) {
10809 /* No file maps to this tablespace ID. It's possible that
10810 the file was deleted later or is misisng. */
10811
10812 1423 return ptr;
10813 }
10814
10815 /* Update filename with correct partition case, if needed. */
10816
1/2
✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
3053 std::string name_str(name);
10817 3053 std::string space_name;
10818
1/2
✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
3053 fil_update_partition_name(page_id.space(), 0, false, space_name, name_str);
10819
10820
1/2
✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
3053 auto abs_name = Fil_path::get_real_path(name_str);
10821
10822 /* Duplicates should have been sorted out before we get here. */
10823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3053 times.
3053 ut_a(result.second->size() == 1);
10824
10825 /* It's possible that the tablespace file was renamed later. */
10826
2/4
✓ Branch 0 taken 3053 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3053 times.
3053 if (result.second->front().compare(abs_name) == 0) {
10827 dberr_t success = fil_tablespace_open_for_recovery(page_id.space());
10828
10829 if (success != DB_SUCCESS) {
10830 ib::info(ER_IB_MSG_356) << "Create '" << abs_name << "' failed!";
10831 }
10832 }
10833 #endif /* UNIV_HOTBACKUP */
10834
10835 3053 return ptr;
10836 4476 }
10837
10838 2138 byte *fil_tablespace_redo_rename(byte *ptr, const byte *end,
10839 const page_id_t &page_id, ulint parsed_bytes,
10840 bool parse_only [[maybe_unused]]) {
10841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
2138 ut_a(page_id.page_no() == 0);
10842
10843 /* We never recreate the system tablespace. */
10844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
2138 ut_a(page_id.space() != TRX_SYS_SPACE);
10845
10846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
2138 ut_a(parsed_bytes != ULINT_UNDEFINED);
10847
10848 /* Where 2 = from name len (uint16_t). */
10849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2138 times.
2138 if (end <= ptr + 2) {
10850 return nullptr;
10851 }
10852
10853 /* Read and check the RENAME FROM_NAME. */
10854 2138 ulint from_len = mach_read_from_2(ptr);
10855 2138 ptr += 2;
10856 2138 char *from_name = reinterpret_cast<char *>(ptr);
10857
10858 /* Check if the 'from' file name is valid. */
10859
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2137 times.
2138 if (end < ptr + from_len) {
10860 1 return nullptr;
10861 }
10862
10863 2137 std::string whats_wrong;
10864 2137 constexpr char more_than_five[] = "The length must be >= 5.";
10865 2137 constexpr char end_with_ibd[] = "The file suffix must be '.ibd'.";
10866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2137 times.
2137 if (from_len < 5) {
10867 recv_sys->found_corrupt_log = true;
10868 whats_wrong.assign(more_than_five);
10869 } else {
10870
1/2
✓ Branch 0 taken 2137 times.
✗ Branch 1 not taken.
2137 std::string name{from_name};
10871
10872
2/4
✓ Branch 0 taken 2137 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2137 times.
2137 if (!Fil_path::has_suffix(IBD, name)) {
10873 recv_sys->found_corrupt_log = true;
10874 whats_wrong.assign(end_with_ibd);
10875 }
10876 2137 }
10877
10878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2137 times.
2137 if (recv_sys->found_corrupt_log) {
10879 ib::info(ER_IB_MSG_357) << "MLOG_FILE_RENAME: Invalid {from} file name: '"
10880 << from_name << "'. " << whats_wrong;
10881
10882 return nullptr;
10883 }
10884
10885 2137 ptr += from_len;
10886 2137 Fil_path::normalize(from_name);
10887
10888 /* Read and check the RENAME TO_NAME. */
10889 2137 ulint to_len = mach_read_from_2(ptr);
10890 2137 ptr += 2;
10891 2137 char *to_name = reinterpret_cast<char *>(ptr);
10892
10893 /* Check if the 'to' file name is valid. */
10894
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2136 times.
2137 if (end < ptr + to_len) {
10895 1 return nullptr;
10896 }
10897
10898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
2136 if (to_len < 5) {
10899 recv_sys->found_corrupt_log = true;
10900 whats_wrong.assign(more_than_five);
10901 } else {
10902
1/2
✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
2136 std::string name{to_name};
10903
10904
2/4
✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2136 times.
2136 if (!Fil_path::has_suffix(IBD, name)) {
10905 recv_sys->found_corrupt_log = true;
10906 whats_wrong.assign(end_with_ibd);
10907 }
10908 2136 }
10909
10910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
2136 if (recv_sys->found_corrupt_log) {
10911 ib::info(ER_IB_MSG_357) << "MLOG_FILE_RENAME: Invalid {to} file name: '"
10912 << to_name << "'. " << whats_wrong;
10913
10914 return nullptr;
10915 }
10916
10917 2136 ptr += to_len;
10918 2136 Fil_path::normalize(to_name);
10919
10920 #ifdef UNIV_HOTBACKUP
10921
10922 if (!parse_only) {
10923 meb_tablespace_redo_rename(page_id, from_name, to_name);
10924 }
10925
10926 #else /* !UNIV_HOTBACKUP */
10927
10928 /* Update filename with correct partition case, if needed. */
10929
1/2
✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
2136 std::string to_name_str(to_name);
10930 2136 std::string space_name;
10931
1/2
✓ Branch 0 taken 2136 times.
✗ Branch 1 not taken.
2136 fil_update_partition_name(page_id.space(), 0, false, space_name, to_name_str);
10932
10933
3/4
✓ Branch 0 taken 482 times.
✓ Branch 1 taken 1654 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 482 times.
2136 if (from_len == to_len && strncmp(to_name, from_name, to_len) == 0) {
10934 ib::error(ER_IB_MSG_360)
10935 << "MLOG_FILE_RENAME: The from and to name are the"
10936 << " same: '" << from_name << "', '" << to_name << "'";
10937
10938 recv_sys->found_corrupt_log = true;
10939
10940 return nullptr;
10941 }
10942
10943 #endif /* UNIV_HOTBACKUP */
10944
10945 2136 return ptr;
10946 2137 }
10947
10948 8370 byte *fil_tablespace_redo_extend(byte *ptr, const byte *end,
10949 const page_id_t &page_id, ulint parsed_bytes,
10950 bool parse_only) {
10951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8370 times.
8370 ut_a(page_id.page_no() == 0);
10952
10953 /* We never recreate the system tablespace. */
10954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8370 times.
8370 ut_a(page_id.space() != TRX_SYS_SPACE);
10955
10956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8370 times.
8370 ut_a(parsed_bytes != ULINT_UNDEFINED);
10957
10958 /* Check for valid offset and size values */
10959
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8368 times.
8370 if (end < ptr + 16) {
10960 2 return nullptr;
10961 }
10962
10963 /* Offset within the file to start writing zeros */
10964
1/2
✓ Branch 0 taken 8368 times.
✗ Branch 1 not taken.
8368 os_offset_t offset = mach_read_from_8(ptr);
10965 8368 ptr += 8;
10966
10967 /* Size of the space which needs to be initialized by
10968 writing zeros */
10969
1/2
✓ Branch 0 taken 8368 times.
✗ Branch 1 not taken.
8368 os_offset_t size = mach_read_from_8(ptr);
10970 8368 ptr += 8;
10971
10972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8368 times.
8368 if (size == 0) {
10973 ib::error(ER_IB_MSG_INCORRECT_SIZE)
10974 << "MLOG_FILE_EXTEND: Incorrect value for size encountered."
10975 << "Redo log corruption found.";
10976 recv_sys->found_corrupt_log = true;
10977 return nullptr;
10978 }
10979
10980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8368 times.
8368 if (parse_only) {
10981 return ptr;
10982 }
10983
10984 #ifndef UNIV_HOTBACKUP
10985 const auto result =
10986
1/2
✓ Branch 0 taken 8368 times.
✗ Branch 1 not taken.
8368 fil_system->get_scanned_filename_by_space_id(page_id.space());
10987
10988
2/2
✓ Branch 0 taken 1904 times.
✓ Branch 1 taken 6464 times.
8368 if (result.second == nullptr) {
10989 /* No files found for this tablespace ID. It's possible that the
10990 files were deleted later. */
10991 1904 return ptr;
10992 }
10993
10994
1/2
✓ Branch 0 taken 6464 times.
✗ Branch 1 not taken.
6464 dberr_t err = fil_tablespace_open_for_recovery(page_id.space());
10995
10996
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6460 times.
6464 if (err != DB_SUCCESS) {
10997 /* fil_tablespace_open_for_recovery may fail if the tablespace being
10998 opened is an undo tablespace which is also marked for truncation.
10999 In such a case, skip processing this redo log further and goto the
11000 next record without doing anything more here. */
11001
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 if (fsp_is_undo_tablespace(page_id.space()) &&
11002 undo::is_active_truncate_log_present(undo::id2num(page_id.space()))) {
11003 return ptr;
11004 }
11005 4 return nullptr;
11006 }
11007
11008 /* Open the space */
11009
1/2
✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
6460 bool success = fil_space_open(page_id.space());
11010
11011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 if (!success) {
11012 return nullptr;
11013 }
11014
11015
1/2
✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
6460 fil_space_t *space = fil_space_get(page_id.space());
11016
11017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(space != nullptr);
11018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(!space->files.empty());
11019
11020 /* Space extension operations on temporary tablespaces
11021 are not redo logged as they are always recreated on
11022 server startup. */
11023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(space->purpose != FIL_TYPE_TEMPORARY);
11024
11025 6460 fil_node_t *file = &space->files.back();
11026
11027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(file != nullptr);
11028
11029
1/2
✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
6460 page_size_t page_size(space->flags);
11030
11031
1/2
✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
6460 size_t phy_page_size = page_size.physical();
11032
11033 /* No one else should be extending this file. */
11034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(!file->is_being_extended);
11035
11036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(offset > 0);
11037
1/2
✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
6460 os_offset_t initial_fsize = os_file_get_size(file->handle);
11038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(offset <= initial_fsize);
11039 /* file->size unit is FSP_EXTENT_SIZE.
11040 Disk-full might cause partial FSP_EXTENT_SIZE extension. */
11041
3/10
✓ Branch 0 taken 6460 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6460 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6460 times.
6460 ut_a(initial_fsize / (phy_page_size * FSP_EXTENT_SIZE) ==
11042 file->size / FSP_EXTENT_SIZE);
11043
11044 /* Because punch_hole flush might recover disk-full situation.
11045 We might be able to extend from the partial extension at the
11046 previous disk-full. So, offset might not be at boundary.
11047 But target is aligned to the page boundary */
11048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6460 times.
6460 ut_a(((offset + size) % phy_page_size) == 0);
11049
11050 /* If the physical size of the file is greater than or equal to the
11051 expected size (offset + size), it means that posix_fallocate was
11052 successfully executed.
11053 However, if the redo log record requests an expected size (offset + size)
11054 which is more than the physical size of the file, it means that
11055 posix_fallocate() either allocated partially (in case of emulated
11056 posix_fallocate) or did not allocate at all. In case posix_fallocate()
11057 fails, the server calls fil_write_zeros to extend the space, which
11058 can also fail after allocating space partially because of reasons like
11059 lack of disk space. The real indicator of how much file was actually
11060 allocated is the physical file size itself.
11061 Write out the 0's in the extended space only if the physical size of
11062 the file is less than the expected size (offset + size). */
11063
11064 /* If the file is already equal or larger than the expected size,
11065 nothing more to do here. */
11066
2/2
✓ Branch 0 taken 6275 times.
✓ Branch 1 taken 185 times.
6460 if ((offset + size) <= initial_fsize) {
11067 6275 return ptr;
11068 }
11069
11070 #if defined(UNIV_DEBUG)
11071 /* Validate that there are no pages in the buffer pool. */
11072
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 buf_must_be_all_freed();
11073 #endif /* UNIV_DEBUG */
11074
11075 /* Adjust the actual allocation size to take care of the allocation
11076 problems described above.
11077 Find out the size by which the file should be extended to have
11078 a file of expected size while ensuring that the already allocated
11079 pages are not overwritten with zeros. */
11080 185 os_offset_t new_ext_size = size - (initial_fsize - offset);
11081
11082 /* Initialize the region starting from current end of file with zeros. */
11083
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 err = fil_write_zeros(file, phy_page_size, initial_fsize, new_ext_size);
11084
11085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 if (err != DB_SUCCESS) {
11086 /* Error writing zeros to the file. */
11087 ib::warn(ER_IB_MSG_320) << "Error while writing " << size << " zeroes to "
11088 << file->name << " starting at offset " << offset;
11089 /* Should return normally. If "return nullptr", it means "broken log"
11090 and will skip to apply the all of following logs. */
11091 }
11092
11093 /* Get the final size of the file and adjust file->size accordingly. */
11094
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 os_offset_t end_fsize = os_file_get_size(file->handle);
11095
11096 185 file->size = end_fsize / phy_page_size;
11097 185 space->size = file->size;
11098
11099
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 fil_flush(space->id);
11100
11101
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 fil_space_close(space->id);
11102 #endif /* !UNIV_HOTBACKUP */
11103
11104 185 return ptr;
11105 8368 }
11106
11107 /** Redo a tablespace delete.
11108 @param[in] ptr redo log record
11109 @param[in] end end of the redo log buffer
11110 @param[in] page_id Tablespace Id and first page in file
11111 @param[in] parsed_bytes Number of bytes parsed so far
11112 @param[in] parse_only Don't apply, parse only
11113 @return pointer to next redo log record
11114 @retval nullptr if this log record was truncated */
11115 4101 byte *fil_tablespace_redo_delete(byte *ptr, const byte *end,
11116 const page_id_t &page_id, ulint parsed_bytes,
11117 bool parse_only) {
11118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
4101 ut_a(page_id.page_no() == 0);
11119
11120 /* We never recreate the system tablespace. */
11121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
4101 ut_a(page_id.space() != TRX_SYS_SPACE);
11122
11123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
4101 ut_a(parsed_bytes != ULINT_UNDEFINED);
11124
11125 /* Where 2 = len (uint16_t). */
11126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4101 times.
4101 if (end <= ptr + 2) {
11127 return nullptr;
11128 }
11129
11130 4101 ulint len = mach_read_from_2(ptr);
11131
11132 4101 ptr += 2;
11133
11134 /* Do we have the full/valid file name. */
11135
2/4
✓ Branch 0 taken 4101 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4101 times.
4101 if (end < ptr + len || len < 5) {
11136 if (len < 5) {
11137 char name[6];
11138
11139 snprintf(name, sizeof(name), "%.*s", (int)len, ptr);
11140
11141 ib::error(ER_IB_MSG_362) << "MLOG_FILE_DELETE : Invalid file name."
11142 << " Length (" << len << ") must be >= 5"
11143 << " and end in '.ibd'. File name in the"
11144 << " redo log is '" << name << "'";
11145 }
11146
11147 return nullptr;
11148 }
11149
11150 4101 char *name = reinterpret_cast<char *>(ptr);
11151
11152 4101 Fil_path::normalize(name);
11153
11154 4101 ptr += len;
11155
11156
7/16
✓ Branch 0 taken 4101 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4101 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 4058 times.
✓ Branch 6 taken 4101 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4101 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4101 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
4144 if (!(Fil_path::has_suffix(IBD, name) ||
11157
2/4
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43 times.
43 fsp_is_undo_tablespace(page_id.space()))) {
11158 recv_sys->found_corrupt_log = true;
11159
11160 return nullptr;
11161 }
11162
11163
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4081 times.
4101 if (parse_only) {
11164 20 return ptr;
11165 }
11166 #ifdef UNIV_HOTBACKUP
11167
11168 meb_tablespace_redo_delete(page_id, name);
11169
11170 #else /* !UNIV_HOTBACKUP */
11171
11172 /* The first condition is true during normal server operation, the
11173 second one during server startup after
11174 recv_recovery_from_checkpoint_start has completed. */
11175
3/6
✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4081 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4081 times.
4081 if (!recv_recovery_is_on() || recv_lsn_checks_on) {
11176 /* We are being called from online log tracking, file name
11177 processing is a no-op, and specifically do not cause any DD
11178 changes. */
11179 return (ptr);
11180 }
11181
11182 const auto result =
11183
1/2
✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
4081 fil_system->get_scanned_filename_by_space_id(page_id.space());
11184
11185
1/2
✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
4081 recv_sys->deleted.insert(page_id.space());
11186
1/2
✓ Branch 0 taken 4081 times.
✗ Branch 1 not taken.
4081 recv_sys->missing_ids.erase(page_id.space());
11187
11188
2/2
✓ Branch 0 taken 4079 times.
✓ Branch 1 taken 2 times.
4081 if (result.second == nullptr) {
11189 /* No files map to this tablespace ID. The drop must
11190 have succeeded. */
11191
11192 4079 return ptr;
11193 }
11194
11195 /* Space_id_set should have been sorted out before we get here. */
11196
11197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ut_a(result.second->size() == 1);
11198
11199 /* Update filename with correct partition case, if needed. */
11200
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 std::string name_str(name);
11201 2 std::string space_name;
11202
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 fil_update_partition_name(page_id.space(), 0, false, space_name, name_str);
11203
11204
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 fil_space_free(page_id.space(), false);
11205
11206
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 bool success = fil_system->erase_path(page_id.space());
11207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ut_a(success);
11208 #endif /* UNIV_HOTBACKUP */
11209
11210 2 return ptr;
11211 4081 }
11212
11213 105 byte *fil_tablespace_redo_encryption(byte *ptr, const byte *end,
11214 space_id_t space_id, lsn_t lsn) {
11215
1/2
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
105 fil_space_t *space = fil_space_get(space_id);
11216
11217 /* An undo space might be open but not have the ENCRYPTION bit set
11218 in its header if the current value of innodb_undo_log_encrypt=OFF
11219 and a crash occurred between flushing this redo record and the header
11220 page of the undo space. So if the flag is missing, ignore the header
11221 page. */
11222
5/10
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 93 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 105 times.
105 if (fsp_is_undo_tablespace(space_id) && space != nullptr &&
11223 !FSP_FLAGS_GET_ENCRYPTION(space->flags)) {
11224 space = nullptr;
11225 }
11226
11227 105 ulint offset = mach_read_from_2(ptr);
11228 105 ptr += 2;
11229
11230 105 const ulint len = mach_read_from_2(ptr);
11231 105 ptr += 2;
11232
11233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
105 if (end < ptr + len) {
11234 return (nullptr);
11235 }
11236
11237
3/6
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 105 times.
105 if (offset >= UNIV_PAGE_SIZE || len + offset > UNIV_PAGE_SIZE ||
11238 len != Encryption::INFO_SIZE) {
11239 recv_sys->found_corrupt_log = true;
11240 return (nullptr);
11241 }
11242
11243 105 byte *encryption_ptr = ptr;
11244 105 ptr += len;
11245
11246 /* If space is already loaded and have header_page_flushed_lsn greater than
11247 this REDO entry LSN, then skip it coz header has latest information. */
11248
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
105 if (space != nullptr && space->m_header_page_flush_lsn > lsn) {
11249 2 return (ptr);
11250 }
11251
11252 /* If encryption info is 0 filled, then this is erasing encryption info
11253 during unencryption operation. Skip decrypting it. */
11254 {
11255 103 byte buf[Encryption::INFO_SIZE] = {0};
11256
11257
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 85 times.
103 if (memcmp(encryption_ptr + 4, buf, Encryption::INFO_SIZE - 4) == 0) {
11258 /* NOTE: We don't need to reset encryption info of space here because it
11259 might be needed. It will be reset when this REDO record is applied. */
11260 18 return (ptr);
11261 }
11262 }
11263
11264 85 byte iv[Encryption::KEY_LEN] = {0};
11265 85 byte key[Encryption::KEY_LEN] = {0};
11266
11267 85 Encryption_key e_key{key, iv};
11268
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 83 times.
85 if (!Encryption::decode_encryption_info(space_id, e_key, encryption_ptr,
11269 true)) {
11270 2 recv_sys->found_corrupt_log = true;
11271
11272
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 ib::warn(ER_IB_MSG_364)
11273
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 << "Encryption information"
11274
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 << " in the redo log of space " << space_id << " is invalid";
11275
11276 2 return (nullptr);
11277 }
11278
11279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 ut_ad(len == Encryption::INFO_SIZE);
11280
11281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (space != nullptr) {
11282 Encryption::set_or_generate(Encryption::AES, key, iv,
11283 space->m_encryption_metadata);
11284 fsp_flags_set_encryption(space->flags);
11285 return ptr;
11286 }
11287
11288 /* Space is not loaded yet. Remember this key in recv_sys and use it later
11289 to pupulate space encryption info once it is loaded. */
11290
3/4
✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 79 times.
83 DBUG_EXECUTE_IF("dont_update_key_found_during_REDO_scan", return ptr;);
11291
11292
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 14 times.
79 if (recv_sys->keys == nullptr) {
11293 130 recv_sys->keys =
11294
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 ut::new_withkey<recv_sys_t::Encryption_Keys>(UT_NEW_THIS_FILE_PSI_KEY);
11295 }
11296
11297 /* Search if key entry already exists for this tablespace, update it. */
11298
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 73 times.
89 for (auto &recv_key : *recv_sys->keys) {
11299
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 if (recv_key.space_id == space_id) {
11300 6 memcpy(recv_key.iv, iv, Encryption::KEY_LEN);
11301 6 memcpy(recv_key.ptr, key, Encryption::KEY_LEN);
11302 6 recv_key.lsn = lsn;
11303 6 return ptr;
11304 }
11305 }
11306
11307 /* No existing entry found, create new one and insert it. */
11308 recv_sys_t::Encryption_Key new_key;
11309 73 new_key.iv = static_cast<byte *>(
11310 73 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, Encryption::KEY_LEN));
11311 73 memcpy(new_key.iv, iv, Encryption::KEY_LEN);
11312 73 new_key.ptr = static_cast<byte *>(
11313 73 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, Encryption::KEY_LEN));
11314 73 memcpy(new_key.ptr, key, Encryption::KEY_LEN);
11315 73 new_key.space_id = space_id;
11316 73 new_key.lsn = lsn;
11317
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 recv_sys->keys->push_back(new_key);
11318
11319 73 return ptr;
11320 }
11321
11322 void Tablespace_dirs::warn_ignore(std::string ignore_path, const char *reason) {
11323 ib::warn(ER_IB_MSG_IGNORE_SCAN_PATH, ignore_path.c_str(), reason);
11324 }
11325
11326 19544 void Tablespace_dirs::add_path(const std::string &path_in, bool is_undo_dir) {
11327 /* Ignore an invalid path. */
11328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19544 times.
19544 if (path_in == "") {
11329 return;
11330 }
11331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19544 times.
19544 if (path_in == "/") {
11332 warn_ignore(path_in,
11333 "the root directory '/' is not allowed to be scanned.");
11334 return;
11335 }
11336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19544 times.
19544 if (std::string::npos != path_in.find('*')) {
11337 warn_ignore(path_in, "it contains '*'.");
11338 return;
11339 }
11340
11341 /* Assume this path is a directory and put a trailing slash on it. */
11342
1/2
✓ Branch 0 taken 19544 times.
✗ Branch 1 not taken.
19544 std::string dir_in(path_in);
11343
1/2
✓ Branch 0 taken 19544 times.
✗ Branch 1 not taken.
19544 Fil_path::append_separator(dir_in);
11344
11345
1/2
✓ Branch 0 taken 19544 times.
✗ Branch 1 not taken.
19544 Fil_path found_path(dir_in, true);
11346
11347 /* Exclude this path if it is a duplicate of a path already stored or
11348 if a previously stored path is an ancestor. Remove any previously stored
11349 path that is a descendant of this path. */
11350
2/2
✓ Branch 0 taken 9981 times.
✓ Branch 1 taken 9887 times.
19868 for (auto it = m_dirs.cbegin(); it != m_dirs.cend(); /* No op */) {
11351
3/4
✓ Branch 0 taken 9981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9657 times.
✓ Branch 3 taken 324 times.
9981 if (it->root().is_same_as(found_path)) {
11352 /* The exact same path is obviously ignored, so there is no need to
11353 log a warning. */
11354 9657 return;
11355 }
11356
11357 /* Check if dir_abs_path is an ancestor of this path */
11358
2/4
✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 324 times.
324 if (it->root().is_ancestor(found_path)) {
11359 /* Descendant directories will be scanned recursively, so don't
11360 add it to the scan list. Log a warning unless this descendant
11361 is the undo directory since it must be supplied even if it is
11362 a descendant of another data location. */
11363 if (!is_undo_dir) {
11364 std::string reason = "it is a sub-directory of '";
11365 reason += it->root().abs_path();
11366 warn_ignore(path_in, reason.c_str());
11367 }
11368 return;
11369 }
11370
11371
2/4
✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 324 times.
324 if (found_path.is_ancestor(it->root())) {
11372 /* This path is an ancestor of an existing dir in fil_system::m_dirs.
11373 The settings have overlapping locations. Put a note about it to
11374 the error log. The undo_dir is added last, so if it is an ancestor,
11375 the descendant was listed as a datafile directory. So always issue
11376 this message*/
11377 std::string reason = "it is a sub-directory of '";
11378 reason += found_path;
11379 warn_ignore(it->root().path(), reason.c_str());
11380
11381 /* It might also be an ancestor to another dir as well, so keep looking.
11382 We must delete this descendant because we know that this ancestor path
11383 will be inserted and all its descendants will be scanned. */
11384 it = m_dirs.erase(it);
11385 } else {
11386 324 it++;
11387 }
11388 }
11389
11390
2/4
✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9887 times.
✗ Branch 3 not taken.
9887 m_dirs.push_back(Tablespace_files{found_path.path()});
11391 9887 return;
11392 19544 }
11393
11394 86 void Tablespace_dirs::add_paths(const std::string &str,
11395 const std::string &delimiters) {
11396 86 std::string::size_type start = 0;
11397 86 std::string::size_type end = 0;
11398
11399 /* Scan until 'start' reaches the end of the string (npos) */
11400 for (;;) {
11401 197 start = str.find_first_not_of(delimiters, end);
11402
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 111 times.
197 if (std::string::npos == start) {
11403 86 break;
11404 }
11405
11406 111 end = str.find_first_of(delimiters, start);
11407
11408
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 const auto path = str.substr(start, end - start);
11409
11410
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 add_path(path);
11411 111 }
11412 86 }
11413
11414 /** Check whether we can rename the file
11415 @param[in] space Tablespace for which to rename
11416 @param[in] name Source file name
11417 @param[in] df Target file that exists on disk
11418 @return DB_SUCCESS if all OK */
11419 173 static dberr_t fil_rename_validate(fil_space_t *space, const std::string &name,
11420 Datafile &&df) {
11421 173 dberr_t err = df.validate_for_recovery(space->id).error;
11422 /* The validate_for_recovery will set space_id, but will close the file. It is
11423 safe to access filepath and space_id. */
11424
11425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 if (err == DB_TABLESPACE_NOT_FOUND) {
11426 /* Tablespace header doesn't contain the expected
11427 tablespace ID. This is can happen during truncate. */
11428
11429 return err;
11430
11431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 } else if (err != DB_SUCCESS) {
11432 ib::warn(ER_IB_MSG_367) << "Failed to read the first page of the"
11433 << " file '" << df.filepath() << "'."
11434 << " You will need to verify and move the"
11435 << " file out of the way retry recovery.";
11436
11437 return err;
11438 }
11439
11440 173 auto file = &space->files.front();
11441
11442
1/2
✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
173 if (strcmp(df.filepath(), file->name) == 0) {
11443 /* Check if already points to the correct file.
11444 Must have the same space ID */
11445
11446
1/2
✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
173 ib::info(ER_IB_MSG_368) << "Tablespace ID already maps to: '"
11447
2/4
✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
✗ Branch 3 not taken.
173 << df.filepath() << "', rename ignored.";
11448
11449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 ut_a(df.space_id() == space->id);
11450
11451 173 return DB_SUCCESS;
11452
11453 } else if (df.space_id() != space->id) {
11454 /* Target file exists on disk but has a different
11455 tablespace ID. The user should manually delete it. */
11456
11457 ib::error(ER_IB_MSG_369)
11458 << "Cannot rename '" << name << "' to '" << df.filepath() << "'. File '"
11459 << df.filepath() << "' tablespace ID " << df.space_id()
11460 << " doesn't match the expected tablespace"
11461 << " ID " << space->id << ". You will need to verify and move '"
11462 << df.filepath() << "' manually and retry recovery!";
11463
11464 return DB_ERROR;
11465 }
11466
11467 /* Target file exists on disk and has the same ID. */
11468
11469 ib::error(ER_IB_MSG_370)
11470 << "Cannot rename '" << name << "' to '" << df.filepath()
11471 << "'. The File '" << df.filepath() << " already exists on"
11472 << " disk. You will need to verify and move either file"
11473 << " manually and retry recovery!";
11474
11475 return DB_ERROR;
11476 }
11477
11478 /** Replay a file rename operation if possible.
11479 @param[in] page_id Space ID and first page number in the file
11480 @param[in] old_name old file name
11481 @param[in] new_name new file name
11482 @return whether the operation was successfully applied (the name did not exist,
11483 or new_name did not exist and name was successfully renamed to new_name) */
11484 694 static bool fil_op_replay_rename(const page_id_t &page_id,
11485 const std::string &old_name,
11486 const std::string &new_name) {
11487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 694 times.
694 ut_ad(page_id.page_no() == 0);
11488
2/4
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 694 times.
694 ut_ad(old_name.compare(new_name) != 0);
11489
2/4
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 694 times.
694 ut_ad(Fil_path::has_suffix(IBD, new_name));
11490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 694 times.
694 ut_ad(page_id.space() != TRX_SYS_SPACE);
11491
11492 /* In order to replay the rename, the following must hold:
11493 1. The new name is not already used.
11494 2. A tablespace exists with the old name.
11495 3. The space ID for that tablespace matches this log entry.
11496 This will prevent unintended renames during recovery. */
11497
11498 694 space_id_t space_id = page_id.space();
11499
1/2
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
694 fil_space_t *space = fil_space_get(space_id);
11500
11501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 694 times.
694 if (space == nullptr) {
11502 return true;
11503 }
11504
11505
1/2
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
694 std::string name{new_name};
11506 {
11507 694 Datafile df;
11508
11509
1/2
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
694 df.set_filepath(name.c_str());
11510
11511
3/4
✓ Branch 0 taken 694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
✓ Branch 3 taken 521 times.
694 if (df.open_read_only(false) == DB_SUCCESS) {
11512
1/2
✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
173 dberr_t err = fil_rename_validate(space, old_name, std::move(df));
11513
11514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 if (err == DB_TABLESPACE_NOT_FOUND) {
11515 /* This can happen during truncate. */
11516 ib::info(ER_IB_MSG_371) << "Tablespace ID mismatch in '" << name << "'";
11517 }
11518 173 return (err == DB_SUCCESS);
11519 }
11520
2/2
✓ Branch 0 taken 521 times.
✓ Branch 1 taken 173 times.
694 }
11521
11522 521 auto path_sep_pos = name.find_last_of(Fil_path::SEPARATOR);
11523
11524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
521 ut_a(path_sep_pos != std::string::npos);
11525
11526 /* Create the database directory for the new name, if
11527 it does not exist yet */
11528
11529
1/2
✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
521 name.resize(path_sep_pos);
11530
11531
1/2
✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
521 bool success = os_file_create_directory(name.c_str(), false);
11532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
521 ut_a(success);
11533
11534 521 auto datadir_pos = name.find_last_of(Fil_path::SEPARATOR);
11535
11536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
521 ut_ad(datadir_pos != std::string::npos);
11537
11538
1/2
✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
521 name.erase(0, datadir_pos + 1);
11539
11540
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
521 ut_ad(!Fil_path::is_separator(name.back()));
11541
11542 /* schema/table separator is always a '/'. */
11543
1/2
✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
521 name.push_back('/');
11544
11545 /* Strip the '.ibd' suffix. */
11546
1/2
✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
521 name.append(new_name.begin() + path_sep_pos + 1, new_name.end() - 4);
11547
11548
2/4
✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 521 times.
521 ut_ad(!Fil_path::has_suffix(IBD, name));
11549
11550 521 const auto ptr = name.c_str();
11551
11552 dberr_t err =
11553
1/2
✓ Branch 0 taken 521 times.
✗ Branch 1 not taken.
521 fil_rename_tablespace(space_id, old_name.c_str(), ptr, new_name.c_str());
11554
11555 /* Stop recovery if this does not succeed. */
11556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
521 ut_a(err == DB_SUCCESS);
11557
11558 521 return true;
11559 694 }
11560
11561 /** Get the tablespace ID from an .ibd and/or an undo tablespace. If the ID is 0
11562 on the first page then try finding the ID with Datafile::find_space_id().
11563 @param[in] filename File name to check
11564 @return s_invalid_space_id if not found, otherwise the space ID */
11565 78701 space_id_t Fil_system::get_tablespace_id(const std::string &filename) {
11566
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 FILE *fp = fopen(filename.c_str(), "rb");
11567
11568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78701 times.
78701 if (fp == nullptr) {
11569 ib::warn(ER_IB_MSG_372) << "Unable to open '" << filename << "'";
11570 return dict_sys_t::s_invalid_space_id;
11571 }
11572
11573 78701 std::vector<space_id_t> space_ids;
11574 78701 auto page_size = srv_page_size;
11575
11576
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 space_ids.reserve(MAX_PAGES_TO_READ);
11577
11578 78701 const auto n_bytes = page_size * MAX_PAGES_TO_READ;
11579
11580
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 std::unique_ptr<byte[]> buf(new byte[n_bytes]);
11581
11582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78701 times.
78701 if (!buf) {
11583 return dict_sys_t::s_invalid_space_id;
11584 }
11585
11586
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 auto pages_read = fread(buf.get(), page_size, MAX_PAGES_TO_READ, fp);
11587
11588
2/4
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78701 times.
78701 DBUG_EXECUTE_IF("invalid_header", pages_read = 0;);
11589
11590 /* Find the space id from the pages read if enough pages could be read.
11591 Fall back to the more heavier method of finding the space id from
11592 Datafile::find_space_id() if pages cannot be read properly. */
11593
2/2
✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 23 times.
78701 if (pages_read >= MAX_PAGES_TO_READ) {
11594 78678 auto bytes_read = pages_read * page_size;
11595
11596 #ifdef POSIX_FADV_DONTNEED
11597 78678 posix_fadvise(fileno(fp), 0, bytes_read, POSIX_FADV_DONTNEED);
11598 #endif /* POSIX_FADV_DONTNEED */
11599
11600
2/2
✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 179 times.
78857 for (page_no_t i = 0; i < MAX_PAGES_TO_READ; ++i) {
11601 78678 const auto off = i * page_size + FIL_PAGE_SPACE_ID;
11602
11603
1/2
✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
78678 if (off == FIL_PAGE_SPACE_ID) {
11604 /* Find out the page size of the tablespace from the first page.
11605 In case of compressed pages, the subsequent pages can be of different
11606 sizes. If MAX_PAGES_TO_READ is changed to a different value, then the
11607 page size of subsequent pages is needed to find out the offset for
11608 space ID. */
11609
11610 78678 auto space_flags_offset = FSP_HEADER_OFFSET + FSP_SPACE_FLAGS;
11611
11612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78678 times.
78678 ut_a(space_flags_offset + 4 < n_bytes);
11613
11614
1/2
✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
78678 const auto flags = mach_read_from_4(buf.get() + space_flags_offset);
11615
11616
1/2
✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
78678 page_size_t space_page_size(flags);
11617
11618
1/2
✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
78678 page_size = space_page_size.physical();
11619 }
11620
11621
2/4
✓ Branch 0 taken 78678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78678 times.
✗ Branch 3 not taken.
78678 space_ids.push_back(mach_read_from_4(buf.get() + off));
11622
11623
2/2
✓ Branch 0 taken 78499 times.
✓ Branch 1 taken 179 times.
78678 if ((i + 1) * page_size >= bytes_read) {
11624 78499 break;
11625 }
11626 }
11627 }
11628
11629
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 fclose(fp);
11630
11631 space_id_t space_id;
11632
11633
2/2
✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 23 times.
78701 if (!space_ids.empty()) {
11634 78678 space_id = space_ids.front();
11635
11636
2/2
✓ Branch 0 taken 78678 times.
✓ Branch 1 taken 78668 times.
157346 for (auto id : space_ids) {
11637
3/4
✓ Branch 0 taken 78668 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78668 times.
78678 if (id == 0 || space_id != id) {
11638 10 space_id = UINT32_UNDEFINED;
11639
11640 10 break;
11641 }
11642 }
11643 } else {
11644 23 space_id = UINT32_UNDEFINED;
11645 }
11646
11647 /* Try the more heavy duty method, as a last resort. */
11648
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 78668 times.
78701 if (space_id == UINT32_UNDEFINED) {
11649 /* If the first page cannot be read properly, then for compressed
11650 tablespaces we don't know where the page boundary starts because
11651 we don't know the page size. */
11652
11653 33 Datafile file;
11654
11655
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 file.set_filepath(filename.c_str());
11656
11657
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 dberr_t err = file.open_read_only(false);
11658
11659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 ut_a(file.is_open());
11660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 ut_a(err == DB_SUCCESS);
11661
11662 /* Use the heavier Datafile::find_space_id() method to
11663 find the space id. */
11664
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 err = file.find_space_id();
11665
11666
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (err == DB_SUCCESS) {
11667 33 space_id = file.space_id();
11668 }
11669
11670
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 file.close();
11671 33 }
11672
11673 78701 return space_id;
11674 78701 }
11675
11676 9723 void Fil_system::rename_partition_files(bool revert) {
11677 #ifndef UNIV_HOTBACKUP
11678 /* If revert, then we are downgrading after upgrade failure from 5.7 */
11679
4/6
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 9693 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9723 times.
9723 ut_ad(!revert || srv_downgrade_partition_files);
11680
11681
2/2
✓ Branch 0 taken 9681 times.
✓ Branch 1 taken 42 times.
9723 if (m_old_paths.empty()) {
11682 9681 return;
11683 }
11684
11685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 ut_ad(!lower_case_file_system);
11686
11687
2/2
✓ Branch 0 taken 499 times.
✓ Branch 1 taken 42 times.
541 for (auto &old_path : m_old_paths) {
11688
2/4
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 499 times.
499 ut_ad(Fil_path::has_suffix(IBD, old_path));
11689
2/4
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 499 times.
499 ut_ad(dict_name::is_partition(old_path));
11690
11691
1/2
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
499 fil_rename_partition_file(old_path, IBD, revert, false);
11692 }
11693 #endif /* !UNIV_HOTBACKUP */
11694 }
11695
11696 19180 void Tablespace_dirs::duplicate_check(const Const_iter &start,
11697 const Const_iter &end, size_t thread_id,
11698 std::mutex *mutex, Space_id_set *unique,
11699 Space_id_set *duplicates) {
11700 19180 size_t count = 0;
11701 19180 bool printed_msg = false;
11702 19180 auto start_time = std::chrono::steady_clock::now();
11703
11704
2/2
✓ Branch 0 taken 78701 times.
✓ Branch 1 taken 19180 times.
97881 for (auto it = start; it != end; ++it, ++m_checked) {
11705
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 const std::string filename = it->second;
11706 78701 auto &files = m_dirs[it->first];
11707
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 const std::string phy_filename = files.path() + filename;
11708
11709 space_id_t space_id;
11710
11711
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 space_id = Fil_system::get_tablespace_id(phy_filename);
11712
11713
2/4
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78701 times.
✗ Branch 3 not taken.
78701 if (space_id != 0 && space_id != dict_sys_t::s_invalid_space_id) {
11714
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 std::lock_guard<std::mutex> guard(*mutex);
11715
11716
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 auto ret = unique->insert(space_id);
11717
11718 size_t n_files;
11719
11720
1/2
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
78701 n_files = files.add(space_id, filename);
11721
11722
3/4
✓ Branch 0 taken 78700 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78700 times.
78701 if (n_files > 1 || !ret.second) {
11723
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 duplicates->insert(space_id);
11724 }
11725
11726
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
78701 } else if (space_id != 0 &&
11727 Fil_path::is_undo_tablespace_name(phy_filename)) {
11728 ib::info(ER_IB_MSG_373) << "Can't determine the undo file tablespace"
11729 << " ID for '" << phy_filename << "', could be"
11730 << " an undo truncate in progress";
11731
11732 } else {
11733 ib::info(ER_IB_MSG_374) << "Ignoring '" << phy_filename << "' invalid"
11734 << " tablespace ID in the header";
11735 }
11736
11737 78701 ++count;
11738
11739
3/6
✓ Branch 0 taken 78701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78701 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 78701 times.
78701 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
11740 ib::info(ER_IB_MSG_375) << "Thread# " << thread_id << " - Checked "
11741 << count << "/" << (end - start) << " files";
11742
11743 start_time = std::chrono::steady_clock::now();
11744
11745 printed_msg = true;
11746 }
11747 78701 }
11748
11749
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19180 times.
19180 if (printed_msg) {
11750 ib::info(ER_IB_MSG_376) << "Checked " << count << " files";
11751 }
11752 19180 }
11753
11754 /** Print the duplicate filenames for a tablespce ID to the log
11755 @param[in] duplicates Duplicate tablespace IDs*/
11756 1 void Tablespace_dirs::print_duplicates(const Space_id_set &duplicates) {
11757 /* Print the duplicate names to the error log. */
11758
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (auto space_id : duplicates) {
11759 1 Dirs files;
11760
11761
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (auto &dir : m_dirs) {
11762
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 const auto names = dir.find_by_id(space_id);
11763
11764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (names == nullptr) {
11765 continue;
11766 }
11767
11768
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 files.insert(files.end(), names->begin(), names->end());
11769 }
11770
11771 /* Fixes the order in the mtr tests. */
11772
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::sort(files.begin(), files.end());
11773
11774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 ut_a(files.size() > 1);
11775
11776
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream oss;
11777
11778
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 oss << "Tablespace ID: " << space_id << " = [";
11779
11780
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (size_t i = 0; i < files.size(); ++i) {
11781
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 oss << "'" << files[i] << "'";
11782
11783
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (i < files.size() - 1) {
11784
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 oss << ", ";
11785 }
11786 }
11787
11788
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 oss << "]" << std::endl;
11789
11790
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 ib::error(ER_IB_MSG_377) << oss.str();
11791 1 }
11792 1 }
11793
11794 1895430 static bool fil_get_partition_file(const std::string &old_path [[maybe_unused]],
11795 ib_file_suffix extn [[maybe_unused]],
11796 std::string &new_path [[maybe_unused]]) {
11797 /* Safe check. Never needed on Windows. */
11798 #ifdef _WIN32
11799 return false;
11800 #else /* WIN32 */
11801
11802 #ifndef UNIV_HOTBACKUP
11803 /* Needed only for case sensitive file system. */
11804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1895430 times.
1895430 if (lower_case_file_system) {
11805 return false;
11806 }
11807
11808 /* Skip if not right file extension. */
11809
3/4
✓ Branch 0 taken 1895430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1835236 times.
✓ Branch 3 taken 60194 times.
1895430 if (!Fil_path::has_suffix(extn, old_path)) {
11810 1835236 return false;
11811 }
11812
11813 /* Check if partitioned table. */
11814
3/4
✓ Branch 0 taken 60194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55353 times.
✓ Branch 3 taken 4841 times.
60194 if (!dict_name::is_partition(old_path)) {
11815 55353 return false;
11816 }
11817
11818 4841 std::string table_name;
11819 /* Get Innodb dictionary name from file path. */
11820
2/4
✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4841 times.
4841 if (!Fil_path::parse_file_path(old_path, extn, table_name)) {
11821 ut_d(ut_error);
11822 ut_o(return false);
11823 }
11824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4841 times.
4841 ut_ad(!table_name.empty());
11825
11826 /* Rebuild partition table name with lower case. */
11827
1/2
✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
4841 std::string save_name(table_name);
11828
1/2
✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
4841 dict_name::rebuild(table_name);
11829
11830
3/4
✓ Branch 0 taken 4841 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3905 times.
✓ Branch 3 taken 936 times.
4841 if (save_name.compare(table_name) == 0) {
11831 3905 return false;
11832 }
11833
11834 /* Build new partition file name. */
11835
1/2
✓ Branch 0 taken 936 times.
✗ Branch 1 not taken.
936 new_path = Fil_path::make_new_path(old_path, table_name, extn);
11836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 936 times.
936 ut_ad(!new_path.empty());
11837 #endif /* !UNIV_HOTBACKUP */
11838
11839 936 return true;
11840 #endif /* WIN32 */
11841 4841 }
11842
11843 #ifndef UNIV_HOTBACKUP
11844 529 static void fil_rename_partition_file(const std::string &old_path,
11845 ib_file_suffix extn, bool revert,
11846 bool import) {
11847 529 std::string new_path;
11848
11849
2/4
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 529 times.
529 if (!fil_get_partition_file(old_path, extn, new_path)) {
11850 ut_d(ut_error);
11851 ut_o(return );
11852 }
11853
11854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 529 times.
529 ut_ad(!new_path.empty());
11855
11856
1/2
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
529 bool old_exists = os_file_exists(old_path.c_str());
11857
1/2
✓ Branch 0 taken 529 times.
✗ Branch 1 not taken.
529 bool new_exists = os_file_exists(new_path.c_str());
11858
11859 static bool print_upgrade = true;
11860 static bool print_downgrade = true;
11861 529 bool ret = false;
11862
11863
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 437 times.
529 if (revert) {
11864 /* Check if rename is required. */
11865
2/4
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 92 times.
92 if (!new_exists || old_exists) {
11866 return;
11867 }
11868
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 ret = os_file_rename(innodb_data_file_key, new_path.c_str(),
11869 old_path.c_str());
11870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 ut_ad(ret);
11871
11872
3/4
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 85 times.
92 if (ret && print_downgrade) {
11873
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ib::info(ER_IB_MSG_DOWNGRADE_PARTITION_FILE, new_path.c_str(),
11874 7 old_path.c_str());
11875 7 print_downgrade = false;
11876 }
11877 92 return;
11878 }
11879
11880 /* Check if rename is required. */
11881
2/4
✓ Branch 0 taken 437 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 437 times.
437 if (new_exists || !old_exists) {
11882 return;
11883 }
11884
11885 ret =
11886
1/2
✓ Branch 0 taken 437 times.
✗ Branch 1 not taken.
437 os_file_rename(innodb_data_file_key, old_path.c_str(), new_path.c_str());
11887
11888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 437 times.
437 if (!ret) {
11889 /* File rename failed. */
11890 ut_d(ut_error);
11891 ut_o(return );
11892 }
11893
11894
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 407 times.
437 if (import) {
11895
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 ib::info(ER_IB_MSG_UPGRADE_PARTITION_FILE_IMPORT, old_path.c_str(),
11896 30 new_path.c_str());
11897 30 return;
11898 }
11899
11900
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 372 times.
407 if (print_upgrade) {
11901
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 ib::info(ER_IB_MSG_UPGRADE_PARTITION_FILE, old_path.c_str(),
11902 35 new_path.c_str());
11903 35 print_upgrade = false;
11904 }
11905
2/2
✓ Branch 0 taken 407 times.
✓ Branch 1 taken 122 times.
529 }
11906 #endif /* !UNIV_HOTBACKUP */
11907
11908 19433 void Tablespace_dirs::set_scan_dir(const std::string &in_directory,
11909 bool is_undo_dir) {
11910
1/2
✓ Branch 0 taken 19433 times.
✗ Branch 1 not taken.
19433 std::string directory(in_directory);
11911
11912 19433 Fil_path::normalize(directory);
11913
11914
1/2
✓ Branch 0 taken 19433 times.
✗ Branch 1 not taken.
19433 add_path(directory, is_undo_dir);
11915 19433 }
11916
11917 86 void Tablespace_dirs::set_scan_dirs(const std::string &in_directories) {
11918
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 std::string directories(in_directories);
11919
11920 86 Fil_path::normalize(directories);
11921
11922 86 std::string separators;
11923
11924
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 separators.push_back(FIL_PATH_SEPARATOR);
11925
11926
1/2
✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
86 add_paths(directories, separators);
11927 86 }
11928
11929 /** Discover tablespaces by reading the header from .ibd files.
11930 @return DB_SUCCESS if all goes well */
11931 9693 dberr_t Tablespace_dirs::scan() {
11932 9693 Scanned_files ibd_files;
11933 9693 Scanned_files undo_files;
11934 9693 uint16_t count = 0;
11935 9693 bool print_msg = false;
11936 9693 auto start_time = std::chrono::steady_clock::now();
11937
11938 /* Should be trivial to parallelize the scan and ID check. */
11939
2/2
✓ Branch 0 taken 9887 times.
✓ Branch 1 taken 9693 times.
19580 for (const auto &dir : m_dirs) {
11940
1/2
✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
9887 const auto real_path_dir = dir.root().abs_path();
11941
11942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9887 times.
9887 ut_a(Fil_path::is_separator(dir.path().back()));
11943
11944
4/8
✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9887 times.
✗ Branch 7 not taken.
9887 ib::info(ER_IB_MSG_379) << "Scanning '" << dir.path() << "'";
11945
11946 /* Walk the sub-tree of dir. */
11947
11948
1/2
✓ Branch 0 taken 9887 times.
✗ Branch 1 not taken.
9887 Dir_Walker::walk(real_path_dir, true, [&](const std::string &path) {
11949 /* If it is a file and the suffix matches ".ibd"
11950 or the undo file name format then store it for
11951 determining the space ID. */
11952
11953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1894901 times.
1894901 ut_a(path.length() > real_path_dir.length());
11954
2/4
✓ Branch 0 taken 1894901 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1894901 times.
1894901 ut_a(Fil_path::get_file_type(path) != OS_FILE_TYPE_DIR);
11955
11956 /* Check if need to alter partition file names to lower case. */
11957 1894901 std::string new_path;
11958
11959
3/4
✓ Branch 0 taken 1894901 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 407 times.
✓ Branch 3 taken 1894494 times.
1894901 if (fil_get_partition_file(path, IBD, new_path)) {
11960 /* Note all old file names to be renamed. */
11961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 407 times.
407 ut_ad(!new_path.empty());
11962
1/2
✓ Branch 0 taken 407 times.
✗ Branch 1 not taken.
407 fil_system->add_old_file(path);
11963
11964 } else {
11965
1/2
✓ Branch 0 taken 1894494 times.
✗ Branch 1 not taken.
1894494 new_path.assign(path);
11966 }
11967
11968 /* Make the filename relative to the directory that was scanned. */
11969
1/2
✓ Branch 0 taken 1894901 times.
✗ Branch 1 not taken.
1894901 std::string file = new_path.substr(real_path_dir.length());
11970
11971
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1894899 times.
1894901 if (file.size() <= 4) {
11972 2 return;
11973 }
11974
11975 using Value = Scanned_files::value_type;
11976
11977
4/6
✓ Branch 0 taken 1894899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1894899 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 59665 times.
✓ Branch 5 taken 1835234 times.
1894899 if (Fil_path::has_suffix(IBD, file.c_str())) {
11978
2/4
✓ Branch 0 taken 59665 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59665 times.
✗ Branch 3 not taken.
59665 ibd_files.push_back(Value{count, file});
11979
11980
3/4
✓ Branch 0 taken 1835234 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19036 times.
✓ Branch 3 taken 1816198 times.
1835234 } else if (Fil_path::is_undo_tablespace_name(file)) {
11981
2/4
✓ Branch 0 taken 19036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19036 times.
✗ Branch 3 not taken.
19036 undo_files.push_back(Value{count, file});
11982 }
11983
11984
3/6
✓ Branch 0 taken 1894899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1894899 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1894899 times.
1894899 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
11985 ib::info(ER_IB_MSG_380)
11986 << "Files found so far: " << ibd_files.size() << " data files"
11987 << " and " << undo_files.size() << " undo files";
11988
11989 start_time = std::chrono::steady_clock::now();
11990 print_msg = true;
11991 }
11992
4/4
✓ Branch 0 taken 1894899 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1894899 times.
✓ Branch 3 taken 2 times.
1894903 });
11993
11994 9887 ++count;
11995 9887 }
11996
11997 /* Rename all old partition files. */
11998
1/2
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
9693 fil_system->rename_partition_files(false);
11999
12000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
9693 if (print_msg) {
12001 ib::info(ER_IB_MSG_381) << "Found " << ibd_files.size() << " '.ibd' and "
12002 << undo_files.size() << " undo files";
12003 }
12004
12005 9693 Space_id_set unique;
12006 9693 Space_id_set duplicates;
12007
12008 /* Get the number of additional threads needed to scan the files. */
12009
1/2
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
9693 size_t n_threads = fil_get_scan_threads(ibd_files.size());
12010
12011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
9693 if (n_threads > 0) {
12012 ib::info(ER_IB_MSG_382)
12013 << "Using " << (n_threads + 1) << " threads to"
12014 << " scan " << ibd_files.size() << " tablespace files";
12015 }
12016
12017 9693 std::mutex m;
12018
12019 using std::placeholders::_1;
12020 using std::placeholders::_2;
12021 using std::placeholders::_3;
12022 using std::placeholders::_4;
12023 using std::placeholders::_5;
12024 using std::placeholders::_6;
12025
12026 std::function<void(const Const_iter &, const Const_iter &, size_t,
12027 std::mutex *, Space_id_set *, Space_id_set *)>
12028
1/2
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
9693 check = std::bind(&Tablespace_dirs::duplicate_check, this, _1, _2, _3, _4,
12029
1/2
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
9693 _5, _6);
12030
12031
1/2
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
9693 par_for(PFS_NOT_INSTRUMENTED, ibd_files, n_threads, check, &m, &unique,
12032 &duplicates);
12033
12034
1/2
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
9693 duplicate_check(undo_files.begin(), undo_files.end(), n_threads, &m, &unique,
12035 &duplicates);
12036
12037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9693 times.
9693 ut_a(m_checked == ibd_files.size() + undo_files.size());
12038
12039
3/6
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9693 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9693 times.
✗ Branch 5 not taken.
29079 ib::info(ER_IB_MSG_383) << "Completed space ID check of " << m_checked.load()
12040
1/2
✓ Branch 0 taken 9693 times.
✗ Branch 1 not taken.
9693 << " files.";
12041
12042 dberr_t err;
12043
12044
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9692 times.
9693 if (!duplicates.empty()) {
12045
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 ib::error(ER_IB_MSG_384)
12046
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 << "Multiple files found for the same tablespace ID:";
12047
12048
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 print_duplicates(duplicates);
12049
12050 1 err = DB_FAIL;
12051 } else {
12052 9692 err = DB_SUCCESS;
12053 }
12054
12055 9693 return err;
12056 9693 }
12057
12058 19433 void fil_set_scan_dir(const std::string &directory, bool is_undo_dir) {
12059 19433 fil_system->set_scan_dir(directory, is_undo_dir);
12060 19433 }
12061
12062 86 void fil_set_scan_dirs(const std::string &directories) {
12063 86 fil_system->set_scan_dirs(directories);
12064 86 }
12065
12066 /** Discover tablespaces by reading the header from .ibd files.
12067 @return DB_SUCCESS if all goes well */
12068 9693 dberr_t fil_scan_for_tablespaces() { return fil_system->scan(); }
12069
12070 /** Check if a path is known to InnoDB meaning that it is in or under
12071 one of the four path settings scanned at startup for file discovery.
12072 @param[in] path Path to check
12073 @return true if path is known to InnoDB */
12074 15110 bool fil_path_is_known(const std::string &path) {
12075 15110 return fil_system->check_path(path);
12076 }
12077
12078 /** Get the list of directories that datafiles can reside in.
12079 @return the list of directories 'dir1;dir2;....;dirN' */
12080 9693 std::string fil_get_dirs() { return fil_system->get_dirs(); }
12081
12082 /** Free the data structures required for recovery. */
12083 9493 void fil_free_scanned_files() { fil_system->free_scanned_files(); }
12084
12085 /** Update the tablespace name. In case, the new name
12086 and old name are same, no update done.
12087 @param[in,out] space tablespace object on which name
12088 will be updated
12089 @param[in] name new name for tablespace */
12090 2928 void fil_space_update_name(fil_space_t *space, const char *name) {
12091
3/6
✓ Branch 0 taken 2928 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2928 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2928 times.
✗ Branch 5 not taken.
2928 if (space == nullptr || name == nullptr || space->name == nullptr ||
12092
2/2
✓ Branch 0 taken 2923 times.
✓ Branch 1 taken 5 times.
2928 strcmp(space->name, name) == 0) {
12093 2923 return;
12094 }
12095
12096 5 dberr_t err = fil_rename_tablespace_by_id(space->id, space->name, name);
12097
12098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (err != DB_SUCCESS) {
12099 ib::warn(ER_IB_MSG_387) << "Tablespace rename '" << space->name << "' to"
12100 << " '" << name << "' failed!";
12101 }
12102 }
12103
12104 #ifndef UNIV_HOTBACKUP
12105 72358 bool Fil_path::is_valid_location(const char *space_name, space_id_t space_id,
12106 uint32_t fsp_flags, const std::string &path) {
12107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
72358 ut_ad(!path.empty());
12108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72358 times.
72358 ut_ad(space_name != nullptr);
12109
12110 /* All files sent to this routine have been found by scanning known
12111 locations. */
12112
2/2
✓ Branch 0 taken 18903 times.
✓ Branch 1 taken 53455 times.
72358 ib_file_suffix type = (fsp_is_undo_tablespace(space_id) ? IBU : IBD);
12113
12114
2/2
✓ Branch 0 taken 53455 times.
✓ Branch 1 taken 18903 times.
72358 if (type == IBD) {
12115
1/2
✓ Branch 0 taken 53455 times.
✗ Branch 1 not taken.
53455 size_t dirname_len = dirname_length(path.c_str());
12116
1/2
✓ Branch 0 taken 53455 times.
✗ Branch 1 not taken.
53455 Fil_path dirpath(path.c_str(), dirname_len, true);
12117
12118 53455 bool is_shared = fsp_is_shared_tablespace(fsp_flags);
12119
1/2
✓ Branch 0 taken 53455 times.
✗ Branch 1 not taken.
53455 bool under_datadir = MySQL_datadir_path.is_ancestor(dirpath);
12120
12121
2/2
✓ Branch 0 taken 9832 times.
✓ Branch 1 taken 43623 times.
53455 if (is_shared) {
12122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9832 times.
9832 if (under_datadir) {
12123 ib::error(ER_IB_MSG_GENERAL_TABLESPACE_UNDER_DATADIR, path.c_str());
12124 return false;
12125 }
12126 } else {
12127 /* file-per-table */
12128 bool in_datadir =
12129
3/4
✓ Branch 0 taken 43476 times.
✓ Branch 1 taken 147 times.
✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
43623 (under_datadir ? false : MySQL_datadir_path.is_same_as(dirpath));
12130
12131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43623 times.
43623 if (in_datadir) {
12132 ib::error(ER_IB_MSG_IMPLICIT_TABLESPACE_IN_DATADIR, path.c_str());
12133 return false;
12134 }
12135
12136 /* Make sure that the last directory of an implicit tablespace is a
12137 filesystem charset version of the schema name. */
12138
3/4
✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 43425 times.
43623 if (!is_valid_location_within_db(space_name, path)) {
12139
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 ib::error(ER_IB_MSG_INVALID_LOCATION_WRONG_DB, path.c_str(),
12140 space_name);
12141 198 return false;
12142 }
12143 }
12144
2/2
✓ Branch 0 taken 53257 times.
✓ Branch 1 taken 198 times.
53455 }
12145
12146 72160 return true;
12147 }
12148
12149 43623 bool Fil_path::is_valid_location_within_db(const char *space_name,
12150 const std::string &path) {
12151 /* Strip off the basename to reduce the path to a directory. */
12152
1/2
✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
43623 std::string dirpath{path};
12153 43623 auto pos = dirpath.find_last_of(SEPARATOR);
12154
1/2
✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
43623 dirpath.resize(pos);
12155
12156 /* Only implicit tablespaces are sent to this routine.
12157 They are always prefixed by `schema/`. */
12158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43623 times.
43623 ut_ad(pos != std::string::npos);
12159
12160 /* Get the subdir that the file is in. */
12161 43623 pos = dirpath.find_last_of(SEPARATOR);
12162 std::string db_dir = (pos == std::string::npos)
12163 ? dirpath
12164
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 43623 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 43623 times.
✗ Branch 5 not taken.
43623 : dirpath.substr(pos + 1, dirpath.length());
12165
12166 /* Convert to lowercase if necessary. */
12167
2/4
✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43623 times.
43623 if (innobase_get_lower_case_table_names() == 2) {
12168 Fil_path::convert_to_lower_case(db_dir);
12169 }
12170
12171 /* Make sure the db_dir matches the schema name.
12172 db_dir is in filesystem charset and space_name is usually in the
12173 system charset.
12174
12175 The problem here is that the system charset version of a schema or
12176 table name may contain a '/' and the tablespace name we were sent
12177 is a combination of the two with '/' as a delimiter.
12178 For example `my/schema` + `my/table` == `my/schema/my/table`
12179
12180 Search the space_name string backwards until we find the db name that
12181 matches the schema name from the path. */
12182
12183
1/2
✓ Branch 0 taken 43623 times.
✗ Branch 1 not taken.
43623 std::string name(space_name);
12184 43623 pos = name.find_last_of(SEPARATOR);
12185
1/2
✓ Branch 0 taken 43842 times.
✗ Branch 1 not taken.
43842 while (pos < std::string::npos) {
12186
1/2
✓ Branch 0 taken 43842 times.
✗ Branch 1 not taken.
43842 name.resize(pos);
12187
1/2
✓ Branch 0 taken 43842 times.
✗ Branch 1 not taken.
43842 std::string temp = name;
12188
2/2
✓ Branch 0 taken 43414 times.
✓ Branch 1 taken 428 times.
43842 if (temp == db_dir) {
12189 43414 return true;
12190 }
12191
12192 /* Convert to filename charset and compare again. */
12193
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 Fil_path::convert_to_filename_charset(temp);
12194
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 417 times.
428 if (temp == db_dir) {
12195 11 return true;
12196 }
12197
12198 /* Still no match, iterate through the next SEPARATOR. */
12199 417 pos = name.find_last_of(SEPARATOR);
12200
12201 /* If end of string is hit, there is no match. */
12202
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 219 times.
417 if (pos == std::string::npos) {
12203 198 return false;
12204 }
12205
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 43623 times.
43842 }
12206
12207 return true;
12208 43623 }
12209
12210 /** Convert filename to the file system charset format.
12211 @param[in,out] name Filename to convert */
12212 428 void Fil_path::convert_to_filename_charset(std::string &name) {
12213 428 uint errors = 0;
12214 char old_name[MAX_TABLE_NAME_LEN + 20];
12215 char filename[MAX_TABLE_NAME_LEN + 20];
12216
12217 428 strncpy(filename, name.c_str(), sizeof(filename) - 1);
12218 428 strncpy(old_name, filename, sizeof(old_name));
12219
12220
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 innobase_convert_to_filename_charset(filename, old_name, MAX_TABLE_NAME_LEN);
12221
12222
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 if (errors == 0) {
12223
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 name.assign(filename);
12224 }
12225 428 }
12226
12227 /** Convert to lower case using the file system charset.
12228 @param[in,out] path Filepath to convert */
12229 void Fil_path::convert_to_lower_case(std::string &path) {
12230 char lc_path[MAX_TABLE_NAME_LEN + 20];
12231
12232 ut_ad(path.length() < sizeof(lc_path) - 1);
12233
12234 strncpy(lc_path, path.c_str(), sizeof(lc_path) - 1);
12235
12236 innobase_casedn_path(lc_path);
12237
12238 path.assign(lc_path);
12239 }
12240
12241 560118 void fil_purge() { fil_system->purge(); }
12242
12243 52927 size_t fil_count_undo_deleted(space_id_t undo_num) {
12244 52927 return fil_system->count_undo_deleted(undo_num);
12245 }
12246
12247 #endif /* !UNIV_HOTBACKUP */
12248
12249 #define PAGE_TYPE(x) \
12250 case x: \
12251 return #x;
12252
12253 12423 const char *fil_get_page_type_str(page_type_t type) noexcept {
12254
13/33
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 182 times.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10915 times.
✓ Branch 7 taken 39 times.
✓ Branch 8 taken 333 times.
✓ Branch 9 taken 21 times.
✓ Branch 10 taken 107 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 163 times.
✓ Branch 18 taken 16 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 9 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✓ Branch 30 taken 2 times.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
12423 switch (type) {
12255 581 PAGE_TYPE(FIL_PAGE_INDEX);
12256 PAGE_TYPE(FIL_PAGE_RTREE);
12257 17 PAGE_TYPE(FIL_PAGE_SDI);
12258 182 PAGE_TYPE(FIL_PAGE_UNDO_LOG);
12259 38 PAGE_TYPE(FIL_PAGE_INODE);
12260 PAGE_TYPE(FIL_PAGE_IBUF_FREE_LIST);
12261 10915 PAGE_TYPE(FIL_PAGE_TYPE_ALLOCATED);
12262 39 PAGE_TYPE(FIL_PAGE_IBUF_BITMAP);
12263 333 PAGE_TYPE(FIL_PAGE_TYPE_SYS);
12264 21 PAGE_TYPE(FIL_PAGE_TYPE_TRX_SYS);
12265 107 PAGE_TYPE(FIL_PAGE_TYPE_FSP_HDR);
12266 PAGE_TYPE(FIL_PAGE_TYPE_XDES);
12267 PAGE_TYPE(FIL_PAGE_TYPE_BLOB);
12268 PAGE_TYPE(FIL_PAGE_TYPE_ZBLOB);
12269 PAGE_TYPE(FIL_PAGE_TYPE_ZBLOB2);
12270 PAGE_TYPE(FIL_PAGE_TYPE_UNKNOWN);
12271 PAGE_TYPE(FIL_PAGE_COMPRESSED);
12272 163 PAGE_TYPE(FIL_PAGE_ENCRYPTED);
12273 16 PAGE_TYPE(FIL_PAGE_COMPRESSED_AND_ENCRYPTED);
12274 PAGE_TYPE(FIL_PAGE_ENCRYPTED_RTREE);
12275 PAGE_TYPE(FIL_PAGE_SDI_BLOB);
12276 PAGE_TYPE(FIL_PAGE_SDI_ZBLOB);
12277 PAGE_TYPE(FIL_PAGE_TYPE_LOB_INDEX);
12278 PAGE_TYPE(FIL_PAGE_TYPE_LOB_DATA);
12279 9 PAGE_TYPE(FIL_PAGE_TYPE_LOB_FIRST);
12280 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FIRST);
12281 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_DATA);
12282 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_INDEX);
12283 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FRAG);
12284 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FRAG_ENTRY);
12285 2 PAGE_TYPE(FIL_PAGE_TYPE_RSEG_ARRAY);
12286 PAGE_TYPE(FIL_PAGE_TYPE_LEGACY_DBLWR);
12287 }
12288 ut_d(ut_error);
12289 ut_o(return "UNKNOWN");
12290 }
12291
12292 14 bool fil_is_page_type_valid(page_type_t type) noexcept {
12293
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (fil_page_type_is_index(type)) {
12294 2 return true;
12295 }
12296
12297
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (type <= FIL_PAGE_TYPE_LAST && type != FIL_PAGE_TYPE_UNUSED) {
12298 12 return true;
12299 }
12300
12301 ut_d(ut_error);
12302 ut_o(return false);
12303 }
12304
12305 std::ostream &Fil_page_header::print(std::ostream &out) const noexcept {
12306 /* Print the header information in the order it is stored. */
12307 out << "[Fil_page_header: FIL_PAGE_OFFSET=" << get_page_no()
12308 << ", FIL_PAGE_TYPE=" << get_page_type()
12309 << ", FIL_PAGE_SPACE_ID=" << get_space_id() << "]";
12310 return out;
12311 }
12312
12313 21209 space_id_t Fil_page_header::get_space_id() const noexcept {
12314 21209 return mach_read_from_4(m_frame + FIL_PAGE_SPACE_ID);
12315 }
12316
12317 21209 page_no_t Fil_page_header::get_page_no() const noexcept {
12318 21209 return mach_read_from_4(m_frame + FIL_PAGE_OFFSET);
12319 }
12320
12321 uint16_t Fil_page_header::get_page_type() const noexcept {
12322 return mach_read_from_2(m_frame + FIL_PAGE_TYPE);
12323 }
12324
12325 64063460 fil_node_t *fil_space_t::get_file_node(page_no_t *page_no) noexcept {
12326
2/2
✓ Branch 0 taken 18705 times.
✓ Branch 1 taken 64044935 times.
64063460 if (files.size() > 1) {
12327
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 18705 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18705 times.
18705 ut_a(id == TRX_SYS_SPACE || purpose == FIL_TYPE_TEMPORARY);
12328
12329
1/2
✓ Branch 0 taken 30517 times.
✗ Branch 1 not taken.
30517 for (auto &f : files) {
12330
2/2
✓ Branch 0 taken 18705 times.
✓ Branch 1 taken 11812 times.
30517 if (f.size > *page_no) {
12331 18705 return &f;
12332 }
12333 11812 *page_no -= f.size;
12334 }
12335
12336
2/2
✓ Branch 0 taken 64045027 times.
✓ Branch 1 taken 36 times.
64044935 } else if (!files.empty()) {
12337 64045027 fil_node_t &f = files.front();
12338
12339
8/8
✓ Branch 0 taken 14532677 times.
✓ Branch 1 taken 49512688 times.
✓ Branch 2 taken 14532141 times.
✓ Branch 3 taken 536 times.
✓ Branch 4 taken 64043870 times.
✓ Branch 5 taken 959 times.
✓ Branch 6 taken 64044442 times.
✓ Branch 7 taken 923 times.
64045046 if ((fsp_is_ibd_tablespace(id) && f.size == 0) || f.size > *page_no) {
12340 /* We do not know the size of a single-table tablespace
12341 before we open the file */
12342 64044442 return &f;
12343 }
12344 /* The page is outside the current bounds of the file. We should not assert
12345 here as we could be loading pages in buffer pool from dump file having pages
12346 from dropped tablespaces. Specifically, for undo tablespace it is possible
12347 to re-use the dropped space ID and the page could be out of bound. We need
12348 to ignore such cases. */
12349 }
12350
12351 959 return nullptr;
12352 }
12353
12354 81889960 bool fil_space_t::is_deleted() const {
12355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81890445 times.
81889960 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12356 81890445 return m_deleted;
12357 }
12358
12359 3346224552 bool fil_space_t::was_not_deleted() const {
12360 /* This is not a critical assertion - if you have this mutex, then possibly
12361 you want to call !is_deleted(). */
12362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1312725881 times.
3346224552 ut_ad(!fil_system->shard_by_id(id)->mutex_owned());
12363 1312725881 return !m_deleted;
12364 }
12365
12366 #ifndef UNIV_HOTBACKUP
12367 35198660 uint32_t fil_space_t::get_current_version() const {
12368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35199423 times.
35198660 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12369 35199423 return m_version;
12370 }
12371 3396635133 uint32_t fil_space_t::get_recent_version() const {
12372 /* This is not a critical assertion - if you have this mutex, then possibly
12373 you want to call get_current_version(). */
12374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1294534164 times.
3396635133 ut_ad(!fil_system->shard_by_id(id)->mutex_owned());
12375 1294534164 return m_version;
12376 }
12377 864131 bool fil_space_t::has_no_references() const {
12378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 864131 times.
864131 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12379 1728262 return m_n_ref_count.load() == 0;
12380 }
12381 2873 size_t fil_space_t::get_reference_count() const {
12382 /* This should be only called on server shutdown. */
12383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2873 times.
2873 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12384 5746 return m_n_ref_count.load();
12385 }
12386
12387 #endif /* !UNIV_HOTBACKUP */
12388
12389 187505 void fil_space_t::set_deleted() {
12390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187505 times.
187505 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187505 times.
187505 ut_a(files.size() == 1);
12392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187505 times.
187505 ut_a(n_pending_ops == 0);
12393
12394 #ifndef UNIV_HOTBACKUP
12395 187505 bump_version();
12396
12397 187505 m_deleted = true;
12398 #endif /* !UNIV_HOTBACKUP */
12399 187505 }
12400
12401 #ifndef UNIV_HOTBACKUP
12402
12403 266880 void fil_space_t::bump_version() {
12404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266880 times.
266880 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
266880 ut_a(files.size() == 1);
12406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
266879 ut_a(n_pending_ops == 0);
12407
12408 /* Bump the version. This will make all pages in buffer pool that reference
12409 the current space version to be stale and freed on first encounter. */
12410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
266879 ut_a(stop_new_ops);
12411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266879 times.
266879 ut_a(!m_deleted);
12412
12413 266879 ++m_version;
12414 266880 }
12415
12416 /** Mark space as corrupt
12417 @param space_id space id */
12418 void fil_space_set_corrupt(space_id_t space_id) {
12419 auto *const shard = fil_system->shard_by_id(space_id);
12420
12421 shard->mutex_acquire();
12422
12423 auto *const space = shard->get_space_by_id(space_id);
12424
12425 if (space) space->is_corrupt = true;
12426
12427 shard->mutex_release();
12428 }
12429
12430 9573 void fil_system_acquire() {
12431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9573 times.
9573 ut_ad(fil_system);
12432 9573 fil_system->mutex_acquire_all();
12433 9573 }
12434
12435 9573 void fil_system_release() {
12436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9573 times.
9573 ut_ad(fil_system);
12437 9573 fil_system->mutex_release_all();
12438 9573 }
12439
12440 2 void fil_lock_shard_by_id(space_id_t space_id) {
12441 2 auto *const shard = fil_system->shard_by_id(space_id);
12442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ut_ad(shard);
12443 2 shard->mutex_acquire();
12444 2 }
12445
12446 2 void fil_unlock_shard_by_id(space_id_t space_id) {
12447 2 auto *const shard = fil_system->shard_by_id(space_id);
12448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ut_ad(shard);
12449 2 shard->mutex_release();
12450 2 }
12451
12452 #endif /* !UNIV_HOTBACKUP */
12453